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

Skip downloading base image layers if they exists in target repository #1840

Merged
merged 69 commits into from
Jul 31, 2019
Merged
Show file tree
Hide file tree
Changes from 59 commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
17f77fc
wip
chanseokoh Jun 7, 2019
3a7c93e
Merge branch 'master' into async-restructure
chanseokoh Jun 7, 2019
705dc67
wip
chanseokoh Jun 8, 2019
449744d
wip
chanseokoh Jun 8, 2019
71567be
wip
chanseokoh Jun 8, 2019
7d436eb
wip
chanseokoh Jun 9, 2019
03525c9
Merge remote-tracking branch 'origin/master' into async-restructure
chanseokoh Jun 10, 2019
cdee3f6
wip
chanseokoh Jun 10, 2019
25a47f5
wip
chanseokoh Jun 10, 2019
bcf23dc
Merge remote-tracking branch 'origin/master' into async-restructure
chanseokoh Jun 10, 2019
3e96f0c
Merge remote-tracking branch 'origin/master' into async-restructure
chanseokoh Jun 10, 2019
936c7bf
wip
chanseokoh Jun 10, 2019
507b9d7
Unwrap nested execution exception
chanseokoh Jun 11, 2019
74020ef
Refactor PushImageStep
chanseokoh Jun 11, 2019
398f50f
Remove PullAndCacheBaseImageLayersStep
chanseokoh Jun 11, 2019
a1bf0c2
variable renaming and minor changes
chanseokoh Jun 11, 2019
5c71c1d
Duplicate small section of code
chanseokoh Jun 11, 2019
2853f53
Unroll nested ExecutionException
chanseokoh Jun 11, 2019
2714a51
Merge branch 'async-restructure' into async-restructure-followup
chanseokoh Jun 12, 2019
2a617f2
Make applicationLayers @Nullable
chanseokoh Jun 13, 2019
c693774
Merge branch 'async-restructure' into async-restructure-followup
chanseokoh Jun 13, 2019
0f6bc13
Cleanup
chanseokoh Jun 14, 2019
2bb59d8
Remove incorrect @VisibleForTesting
chanseokoh Jun 17, 2019
b966f5e
Merge branch 'async-restructure' into async-restructure-followup
chanseokoh Jun 17, 2019
6ee9ef0
Refactor code
chanseokoh Jun 17, 2019
2555cca
Merge branch 'master' into async-restructure-followup
chanseokoh Jun 21, 2019
1575676
Delete files
chanseokoh Jun 21, 2019
b1c3722
Revert renaming
chanseokoh Jun 21, 2019
a758b43
Merge branch 'master' into async-restructure-followup
chanseokoh Jun 24, 2019
5db4125
Fix Nullaway
chanseokoh Jun 24, 2019
543c9c5
Merge branch 'master' into i1673-skip-download-base-layers
chanseokoh Jun 26, 2019
2889b04
Prototyping (inefficient)
chanseokoh Jun 26, 2019
e8a5506
wip
chanseokoh Jun 27, 2019
ea165f8
Minor fixes
chanseokoh Jun 27, 2019
b707c43
Merge branch 'minor-fixes' into i1673-skip-download-base-layers
chanseokoh Jun 27, 2019
498d2b5
Merge branch 'master' into async-restructure-followup
chanseokoh Jun 27, 2019
2e99761
Merge branch 'async-restructure-followup' into i1673-skip-download-ba…
chanseokoh Jun 27, 2019
f78954a
wip
chanseokoh Jun 27, 2019
6451d02
Merge branch 'master' into i1673-skip-download-base-layers
chanseokoh Jul 9, 2019
b723d54
Introduce PreparedLayer
chanseokoh Jul 10, 2019
ff71701
Merge remote-tracking branch 'origin/master' into i1673-skip-download…
chanseokoh Jul 10, 2019
e0e75e0
Refactor code
chanseokoh Jul 10, 2019
ed70606
wip
chanseokoh Jul 11, 2019
86d7d3f
Clean up code
chanseokoh Jul 11, 2019
68d0b82
Revert
chanseokoh Jul 11, 2019
9b51f30
Add new system property
chanseokoh Jul 11, 2019
934e019
Update Javadoc
chanseokoh Jul 11, 2019
455a201
Merge branch 'master' into i1673-skip-download-base-layers
chanseokoh Jul 17, 2019
36c441a
Add PushBlobStepTest
chanseokoh Jul 17, 2019
1a2020e
Add PullAndCacheBaseImageLayerStepTest
chanseokoh Jul 17, 2019
e0b21e8
Clean up
chanseokoh Jul 17, 2019
d5c5cb8
Add integration test
chanseokoh Jul 22, 2019
14ef045
doBlobCheck --> forcePush and flip values
chanseokoh Jul 22, 2019
d41c761
renmaing and comments only
chanseokoh Jul 22, 2019
2661495
Rename to ObtainBaseImageLayerStep
chanseokoh Jul 22, 2019
004b3bb
jib.forceDownload --> jib.cacheBaseImage (property renamed)
chanseokoh Jul 23, 2019
4c2a70e
Update error message
chanseokoh Jul 23, 2019
707d920
Rename variable
chanseokoh Jul 23, 2019
05973e2
Remove stray comment
chanseokoh Jul 23, 2019
9914261
Rename method and variables
chanseokoh Jul 23, 2019
4d35db6
Address review comments
chanseokoh Jul 25, 2019
5fd7baa
Go back to Boolean jib.alwaysCacheBaseImage
chanseokoh Jul 30, 2019
4f9e459
Use openjdk8 on Travis instead of oraclejdk8
chanseokoh Jul 30, 2019
21d734e
Ubuntu Trusty
chanseokoh Jul 30, 2019
ded043a
comments
chanseokoh Jul 30, 2019
a9f5a98
Merge remote-tracking branch 'origin/travis-openjdk8' into i1673-skip…
chanseokoh Jul 30, 2019
fdc576c
Merge branch 'master' into i1673-skip-download-base-layers
chanseokoh Jul 30, 2019
b0fe3cf
Rename variable
chanseokoh Jul 30, 2019
3f1b512
Merge remote-tracking branch 'origin/master' into i1673-skip-download…
chanseokoh Jul 30, 2019
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
2 changes: 0 additions & 2 deletions jib-core/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ All notable changes to this project will be documented in this file.

## [unreleased]

### Added

chanseokoh marked this conversation as resolved.
Show resolved Hide resolved
### Changed

- `JibContainerBuilder#addDependencies` is now split into three methods: `addDependencies`, `addSnapshotDependencies`, `addProjectDependencies` ([#1773](https://github.com/GoogleContainerTools/jib/pull/1773))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
import java.util.concurrent.Callable;

/** Builds and caches application layers. */
class BuildAndCacheApplicationLayerStep implements Callable<CachedLayerAndName> {
class BuildAndCacheApplicationLayerStep implements Callable<PreparedLayer> {

private static final String DESCRIPTION = "Building %s layer";

Expand Down Expand Up @@ -86,7 +86,7 @@ private BuildAndCacheApplicationLayerStep(
}

@Override
public CachedLayerAndName call() throws IOException, CacheCorruptedException {
public PreparedLayer call() throws IOException, CacheCorruptedException {
String description = String.format(DESCRIPTION, layerName);

EventHandlers eventHandlers = buildConfiguration.getEventHandlers();
Expand All @@ -101,7 +101,7 @@ public CachedLayerAndName call() throws IOException, CacheCorruptedException {
Optional<CachedLayer> optionalCachedLayer =
cache.retrieve(layerConfiguration.getLayerEntries());
if (optionalCachedLayer.isPresent()) {
return new CachedLayerAndName(optionalCachedLayer.get(), layerName);
return new PreparedLayer.Builder(optionalCachedLayer.get()).setName(layerName).build();
}

Blob layerBlob = new ReproducibleLayerBuilder(layerConfiguration.getLayerEntries()).build();
Expand All @@ -110,7 +110,7 @@ public CachedLayerAndName call() throws IOException, CacheCorruptedException {

eventHandlers.dispatch(LogEvent.debug(description + " built " + cachedLayer.getDigest()));

return new CachedLayerAndName(cachedLayer, layerName);
return new PreparedLayer.Builder(cachedLayer).setName(layerName).build();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
import com.google.cloud.tools.jib.image.Image;
import com.google.cloud.tools.jib.image.LayerPropertyNotFoundException;
import com.google.cloud.tools.jib.image.json.HistoryEntry;
import com.google.common.base.Verify;
import com.google.common.collect.ImmutableList;
import java.time.Instant;
import java.util.List;
Expand All @@ -40,15 +39,15 @@ class BuildImageStep implements Callable<Image> {
private final BuildConfiguration buildConfiguration;
private final ProgressEventDispatcher.Factory progressEventDispatcherFactory;
private final Image baseImage;
private final List<CachedLayerAndName> baseImageLayers;
private final List<CachedLayerAndName> applicationLayers;
private final List<PreparedLayer> baseImageLayers;
private final List<PreparedLayer> applicationLayers;

BuildImageStep(
BuildConfiguration buildConfiguration,
ProgressEventDispatcher.Factory progressEventDispatcherFactory,
Image baseImage,
List<CachedLayerAndName> baseImageLayers,
List<CachedLayerAndName> applicationLayers) {
List<PreparedLayer> baseImageLayers,
List<PreparedLayer> applicationLayers) {
this.buildConfiguration = buildConfiguration;
this.progressEventDispatcherFactory = progressEventDispatcherFactory;
this.baseImage = baseImage;
Expand All @@ -68,9 +67,7 @@ public Image call() throws LayerPropertyNotFoundException {
buildConfiguration.getContainerConfiguration();

// Base image layers
for (CachedLayerAndName baseImageLayer : baseImageLayers) {
imageBuilder.addLayer(baseImageLayer.getCachedLayer());
}
baseImageLayers.stream().forEach(imageBuilder::addLayer);

// Passthrough config and count non-empty history entries
int nonEmptyLayerCount = 0;
Expand Down Expand Up @@ -104,15 +101,15 @@ public Image call() throws LayerPropertyNotFoundException {
}

// Add built layers/configuration
for (CachedLayerAndName applicationLayer : applicationLayers) {
for (PreparedLayer applicationLayer : applicationLayers) {
imageBuilder
.addLayer(applicationLayer.getCachedLayer())
.addLayer(applicationLayer)
.addHistory(
HistoryEntry.builder()
.setCreationTimestamp(layerCreationTime)
.setAuthor("Jib")
.setCreatedBy(buildConfiguration.getToolName() + ":" + ProjectInfo.VERSION)
.setComment(Verify.verifyNotNull(applicationLayer.getName()))
.setComment(applicationLayer.getName())
.build());
}
if (containerConfiguration != null) {
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package com.google.cloud.tools.jib.builder.steps;

import com.google.cloud.tools.jib.api.DescriptorDigest;
import com.google.cloud.tools.jib.api.RegistryException;
import com.google.cloud.tools.jib.builder.ProgressEventDispatcher;
import com.google.cloud.tools.jib.builder.TimerEventDispatcher;
import com.google.cloud.tools.jib.builder.steps.PullBaseImageStep.ImageAndAuthorization;
Expand All @@ -27,6 +28,7 @@
import com.google.cloud.tools.jib.http.Authorization;
import com.google.cloud.tools.jib.image.Layer;
import com.google.cloud.tools.jib.registry.RegistryClient;
import com.google.common.base.Verify;
import com.google.common.collect.ImmutableList;
import java.io.IOException;
import java.util.ArrayList;
Expand All @@ -36,14 +38,49 @@
import javax.annotation.Nullable;

/** Pulls and caches a single base image layer. */
class PullAndCacheBaseImageLayerStep implements Callable<CachedLayerAndName> {
class ObtainBaseImageLayerStep implements Callable<PreparedLayer> {

private static final String DESCRIPTION = "Pulling base image layer %s";

static ImmutableList<PullAndCacheBaseImageLayerStep> makeList(
@FunctionalInterface
private interface BlobExistenceChecker {

Optional<Boolean> exists(DescriptorDigest digest) throws IOException, RegistryException;
}

static ImmutableList<ObtainBaseImageLayerStep> makeListForForcedDownload(
BuildConfiguration buildConfiguration,
ProgressEventDispatcher.Factory progressEventDispatcherFactory,
ImageAndAuthorization baseImageAndAuth) {
BlobExistenceChecker noOpBlobChecker = ignored -> Optional.empty();
return makeList(
buildConfiguration, progressEventDispatcherFactory, baseImageAndAuth, noOpBlobChecker);
}

static ImmutableList<ObtainBaseImageLayerStep> makeListForSelectiveDownload(
BuildConfiguration buildConfiguration,
ProgressEventDispatcher.Factory progressEventDispatcherFactory,
ImageAndAuthorization baseImageAndAuth,
Authorization pushAuthorization) {
Verify.verify(!buildConfiguration.isOffline());

RegistryClient targetRegistryClient =
buildConfiguration
.newTargetImageRegistryClientFactory()
.setAuthorization(pushAuthorization)
.newRegistryClient();
BlobExistenceChecker blobExistenceChecker =
digest -> Optional.of(targetRegistryClient.checkBlob(digest).isPresent());
chanseokoh marked this conversation as resolved.
Show resolved Hide resolved

return makeList(
buildConfiguration, progressEventDispatcherFactory, baseImageAndAuth, blobExistenceChecker);
}

private static ImmutableList<ObtainBaseImageLayerStep> makeList(
BuildConfiguration buildConfiguration,
ProgressEventDispatcher.Factory progressEventDispatcherFactory,
ImageAndAuthorization baseImageAndAuth,
BlobExistenceChecker blobExistenceChecker) {
ImmutableList<Layer> baseImageLayers = baseImageAndAuth.getImage().getLayers();

try (ProgressEventDispatcher progressEventDispatcher =
Expand All @@ -53,14 +90,15 @@ static ImmutableList<PullAndCacheBaseImageLayerStep> makeList(
new TimerEventDispatcher(
buildConfiguration.getEventHandlers(), "Preparing base image layer pullers")) {

List<PullAndCacheBaseImageLayerStep> layerPullers = new ArrayList<>();
List<ObtainBaseImageLayerStep> layerPullers = new ArrayList<>();
for (Layer layer : baseImageLayers) {
layerPullers.add(
new PullAndCacheBaseImageLayerStep(
new ObtainBaseImageLayerStep(
buildConfiguration,
progressEventDispatcher.newChildProducer(),
layer.getBlobDescriptor().getDigest(),
baseImageAndAuth.getAuthorization()));
layer,
baseImageAndAuth.getAuthorization(),
blobExistenceChecker));
}
return ImmutableList.copyOf(layerPullers);
}
Expand All @@ -69,38 +107,50 @@ static ImmutableList<PullAndCacheBaseImageLayerStep> makeList(
private final BuildConfiguration buildConfiguration;
private final ProgressEventDispatcher.Factory progressEventDispatcherFactory;

private final DescriptorDigest layerDigest;
private final Layer layer;
private final @Nullable Authorization pullAuthorization;
private final BlobExistenceChecker blobExistenceChecker;

PullAndCacheBaseImageLayerStep(
ObtainBaseImageLayerStep(
BuildConfiguration buildConfiguration,
ProgressEventDispatcher.Factory progressEventDispatcherFactory,
DescriptorDigest layerDigest,
@Nullable Authorization pullAuthorization) {
Layer layer,
@Nullable Authorization pullAuthorization,
BlobExistenceChecker blobExistenceChecker) {
this.buildConfiguration = buildConfiguration;
this.progressEventDispatcherFactory = progressEventDispatcherFactory;
this.layerDigest = layerDigest;
this.layer = layer;
this.pullAuthorization = pullAuthorization;
this.blobExistenceChecker = blobExistenceChecker;
}

@Override
public CachedLayerAndName call() throws IOException, CacheCorruptedException {
public PreparedLayer call() throws IOException, CacheCorruptedException, RegistryException {
DescriptorDigest layerDigest = layer.getBlobDescriptor().getDigest();
try (ProgressEventDispatcher progressEventDispatcher =
progressEventDispatcherFactory.create("checking base image layer " + layerDigest, 1);
TimerEventDispatcher ignored =
new TimerEventDispatcher(
buildConfiguration.getEventHandlers(), String.format(DESCRIPTION, layerDigest))) {

Optional<Boolean> layerExists = blobExistenceChecker.exists(layerDigest);
briandealwis marked this conversation as resolved.
Show resolved Hide resolved
if (layerExists.orElse(false)) {
return new PreparedLayer.Builder(layer).setStateInTarget(layerExists).build();
}

Cache cache = buildConfiguration.getBaseImageLayersCache();

// Checks if the layer already exists in the cache.
Optional<CachedLayer> optionalCachedLayer = cache.retrieve(layerDigest);
if (optionalCachedLayer.isPresent()) {
return new CachedLayerAndName(optionalCachedLayer.get(), null);
CachedLayer cachedLayer = optionalCachedLayer.get();
return new PreparedLayer.Builder(cachedLayer).setStateInTarget(layerExists).build();
} else if (buildConfiguration.isOffline()) {
throw new IOException(
"Cannot run Jib in offline mode; local Jib cache for base image is missing image layer "
+ layerDigest
+ ". You may need to rerun Jib in online mode to re-download the base image layers.");
+ ". Rerun Jib in online mode with \"-Djib.cacheBaseImage=always\" to re-download "
+ "the base image layers.");
}

RegistryClient registryClient =
Expand All @@ -119,7 +169,7 @@ public CachedLayerAndName call() throws IOException, CacheCorruptedException {
layerDigest,
progressEventDispatcherWrapper::setProgressTarget,
progressEventDispatcherWrapper::dispatchProgress));
return new CachedLayerAndName(cachedLayer, null);
return new PreparedLayer.Builder(cachedLayer).setStateInTarget(layerExists).build();
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
* Copyright 2019 Google LLC.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/

package com.google.cloud.tools.jib.builder.steps;

import com.google.cloud.tools.jib.api.DescriptorDigest;
import com.google.cloud.tools.jib.blob.Blob;
import com.google.cloud.tools.jib.blob.BlobDescriptor;
import com.google.cloud.tools.jib.image.Layer;
import java.util.Optional;

/**
* Layer prepared from {@link BuildAndCacheApplicationLayerStep} and {@link
* ObtainBaseImageLayerStep} to hold information about either a base image layer or an application
* layer.
*/
class PreparedLayer implements Layer {

static class Builder {

private Layer layer;
private String name = "unnamed layer";
private Optional<Boolean> stateInTarget = Optional.empty();

Builder(Layer layer) {
this.layer = layer;
}

Builder setName(String name) {
this.name = name;
return this;
}

/** Sets whether the layer exists in a target destination. Empty (absence) means unknown. */
Builder setStateInTarget(Optional<Boolean> stateInTarget) {
this.stateInTarget = stateInTarget;
return this;
}

PreparedLayer build() {
return new PreparedLayer(layer, name, stateInTarget);
}
}

private final Layer layer;
private final String name;
private final Optional<Boolean> stateInTarget;

private PreparedLayer(Layer layer, String name, Optional<Boolean> stateInTarget) {
this.layer = layer;
this.name = name;
this.stateInTarget = stateInTarget;
}

String getName() {
return name;
}

Optional<Boolean> existsInTarget() {
return stateInTarget;
}

@Override
public Blob getBlob() {
return layer.getBlob();
}

@Override
public BlobDescriptor getBlobDescriptor() {
return layer.getBlobDescriptor();
}

@Override
public DescriptorDigest getDiffId() {
return layer.getDiffId();
}
}
Loading