Skip to content

Commit

Permalink
Fixes using base image from registry that requires token authenticati…
Browse files Browse the repository at this point in the history
…on. (#549)
  • Loading branch information
coollog authored Jul 11, 2018
1 parent ac29205 commit d735f70
Show file tree
Hide file tree
Showing 17 changed files with 187 additions and 88 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import com.google.cloud.tools.jib.cache.Caches;
import com.google.cloud.tools.jib.frontend.ExposedPortsParser;
import com.google.cloud.tools.jib.image.ImageReference;
import com.google.cloud.tools.jib.image.InvalidImageReferenceException;
import com.google.cloud.tools.jib.registry.LocalRegistry;
import java.io.IOException;
import java.net.URISyntaxException;
Expand All @@ -32,6 +33,7 @@
import java.util.concurrent.ExecutionException;
import org.hamcrest.CoreMatchers;
import org.junit.Assert;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
Expand All @@ -46,28 +48,28 @@ public class BuildStepsIntegrationTest {

@Rule public TemporaryFolder temporaryCacheDirectory = new TemporaryFolder();

private SourceFilesConfiguration sourceFilesConfiguration;

@Before
public void setUp() throws IOException, URISyntaxException {
sourceFilesConfiguration = new TestSourceFilesConfiguration();
}

@Test
public void testSteps_forBuildToDockerRegistry()
throws IOException, URISyntaxException, InterruptedException, CacheMetadataCorruptedException,
ExecutionException, CacheDirectoryNotOwnedException, CacheDirectoryCreationException {
SourceFilesConfiguration sourceFilesConfiguration = new TestSourceFilesConfiguration();
BuildConfiguration buildConfiguration =
BuildConfiguration.builder(logger)
.setBaseImage(ImageReference.of("gcr.io", "distroless/java", "latest"))
.setTargetImage(ImageReference.of("localhost:5000", "testimage", "testtag"))
.setMainClass("HelloWorld")
.setJavaArguments(Collections.singletonList("An argument."))
.setExposedPorts(
ExposedPortsParser.parse(Arrays.asList("1000", "2000-2002/tcp", "3000/udp")))
.setAllowHttp(true)
.build();

Path cacheDirectory = temporaryCacheDirectory.newFolder().toPath();
throws IOException, InterruptedException, CacheMetadataCorruptedException, ExecutionException,
CacheDirectoryNotOwnedException, CacheDirectoryCreationException {
BuildSteps buildImageSteps =
BuildSteps.forBuildToDockerRegistry(
buildConfiguration,
sourceFilesConfiguration,
new Caches.Initializer(cacheDirectory, false, cacheDirectory, false));
getBuildSteps(
BuildConfiguration.builder(logger)
.setBaseImage(ImageReference.of("gcr.io", "distroless/java", "latest"))
.setTargetImage(ImageReference.of("localhost:5000", "testimage", "testtag"))
.setMainClass("HelloWorld")
.setJavaArguments(Collections.singletonList("An argument."))
.setExposedPorts(
ExposedPortsParser.parse(Arrays.asList("1000", "2000-2002/tcp", "3000/udp")))
.setAllowHttp(true)
.build());

long lastTime = System.nanoTime();
buildImageSteps.run();
Expand All @@ -91,11 +93,31 @@ public void testSteps_forBuildToDockerRegistry()
"Hello, world. An argument.\n", new Command("docker", "run", imageReference).run());
}

@Test
public void testSteps_forBuildToDockerRegistry_dockerHubBaseImage()
throws InvalidImageReferenceException, IOException, InterruptedException, ExecutionException,
CacheDirectoryCreationException, CacheMetadataCorruptedException,
CacheDirectoryNotOwnedException {
getBuildSteps(
BuildConfiguration.builder(logger)
.setBaseImage(ImageReference.parse("openjdk:8-jre-alpine"))
.setTargetImage(ImageReference.of("localhost:5000", "testimage", "testtag"))
.setMainClass("HelloWorld")
.setJavaArguments(Collections.singletonList("An argument."))
.setAllowHttp(true)
.build())
.run();

String imageReference = "localhost:5000/testimage:testtag";
new Command("docker", "pull", imageReference).run();
Assert.assertEquals(
"Hello, world. An argument.\n", new Command("docker", "run", imageReference).run());
}

@Test
public void testSteps_forBuildToDockerDaemon()
throws IOException, URISyntaxException, InterruptedException, CacheMetadataCorruptedException,
ExecutionException, CacheDirectoryNotOwnedException, CacheDirectoryCreationException {
SourceFilesConfiguration sourceFilesConfiguration = new TestSourceFilesConfiguration();
throws IOException, InterruptedException, CacheMetadataCorruptedException, ExecutionException,
CacheDirectoryNotOwnedException, CacheDirectoryCreationException {
BuildConfiguration buildConfiguration =
BuildConfiguration.builder(logger)
.setBaseImage(ImageReference.of("gcr.io", "distroless/java", "latest"))
Expand All @@ -107,13 +129,12 @@ public void testSteps_forBuildToDockerDaemon()
.build();

Path cacheDirectory = temporaryCacheDirectory.newFolder().toPath();
BuildSteps buildDockerSteps =
BuildSteps.forBuildToDockerDaemon(
BuildSteps.forBuildToDockerDaemon(
buildConfiguration,
sourceFilesConfiguration,
new Caches.Initializer(cacheDirectory, false, cacheDirectory, false));
new Caches.Initializer(cacheDirectory, false, cacheDirectory, false))
.run();

buildDockerSteps.run();
Assert.assertThat(
new Command("docker", "inspect", "testdocker").run(),
CoreMatchers.containsString(
Expand All @@ -126,4 +147,12 @@ public void testSteps_forBuildToDockerDaemon()
Assert.assertEquals(
"Hello, world. An argument.\n", new Command("docker", "run", "testdocker").run());
}

private BuildSteps getBuildSteps(BuildConfiguration buildConfiguration) throws IOException {
Path cacheDirectory = temporaryCacheDirectory.newFolder().toPath();
return BuildSteps.forBuildToDockerRegistry(
buildConfiguration,
sourceFilesConfiguration,
new Caches.Initializer(cacheDirectory, false, cacheDirectory, false));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import com.google.cloud.tools.jib.http.Authorization;
import java.io.IOException;
import org.junit.Assert;
import org.junit.Test;

/** Integration tests for {@link AuthenticationMethodRetriever}. */
Expand All @@ -27,14 +28,15 @@ public class AuthenticationMethodRetrieverIntegrationTest {
public void testGetRegistryAuthenticator()
throws RegistryAuthenticationFailedException, IOException, RegistryException {
RegistryClient registryClient =
RegistryClient.factory("registry.hub.docker.com", "library/busybox")
.newWithAuthorization(null);
RegistryClient.factory("registry.hub.docker.com", "library/busybox").newRegistryClient();
RegistryAuthenticator registryAuthenticator = registryClient.getRegistryAuthenticator();
Assert.assertNotNull(registryAuthenticator);
Authorization authorization = registryAuthenticator.authenticatePull();

RegistryClient authorizedRegistryClient =
RegistryClient.factory("registry.hub.docker.com", "library/busybox")
.newWithAuthorization(authorization);
.setAuthorization(authorization)
.newRegistryClient();
authorizedRegistryClient.pullManifest("latest");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public class BlobCheckerIntegrationTest {
@Test
public void testCheck_exists() throws IOException, RegistryException {
RegistryClient registryClient =
RegistryClient.factory("localhost:5000", "busybox").newAllowHttp();
RegistryClient.factory("localhost:5000", "busybox").setAllowHttp(true).newRegistryClient();
V22ManifestTemplate manifestTemplate =
registryClient.pullManifest("latest", V22ManifestTemplate.class);
DescriptorDigest blobDigest = manifestTemplate.getLayers().get(0).getDigest();
Expand All @@ -43,7 +43,7 @@ public void testCheck_exists() throws IOException, RegistryException {
@Test
public void testCheck_doesNotExist() throws IOException, RegistryException, DigestException {
RegistryClient registryClient =
RegistryClient.factory("localhost:5000", "busybox").newAllowHttp();
RegistryClient.factory("localhost:5000", "busybox").setAllowHttp(true).newRegistryClient();
DescriptorDigest fakeBlobDigest =
DescriptorDigest.fromHash(
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public class BlobPullerIntegrationTest {
public void testPull() throws IOException, RegistryException {
// Pulls the busybox image.
RegistryClient registryClient =
RegistryClient.factory("localhost:5000", "busybox").newAllowHttp();
RegistryClient.factory("localhost:5000", "busybox").setAllowHttp(true).newRegistryClient();
V21ManifestTemplate manifestTemplate =
registryClient.pullManifest("latest", V21ManifestTemplate.class);

Expand All @@ -64,7 +64,9 @@ public void testPull_unknownBlob() throws RegistryException, IOException, Digest

try {
RegistryClient registryClient =
RegistryClient.factory("localhost:5000", "busybox").newAllowHttp();
RegistryClient.factory("localhost:5000", "busybox")
.setAllowHttp(true)
.newRegistryClient();
registryClient.pullBlob(nonexistentDigest, Mockito.mock(OutputStream.class));
Assert.fail("Trying to pull nonexistent blob should have errored");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ public void testPush() throws DigestException, IOException, RegistryException {
"52a9e4d4ba4333ce593707f98564fee1e6d898db0d3602408c0b2a6a424d357c");

RegistryClient registryClient =
RegistryClient.factory("localhost:5000", "testimage").newAllowHttp();
RegistryClient.factory("localhost:5000", "testimage")
.setAllowHttp(true)
.newRegistryClient();
Assert.assertFalse(registryClient.pushBlob(testBlobDigest, testBlob));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public class ManifestPullerIntegrationTest {
@Test
public void testPull_v21() throws IOException, RegistryException {
RegistryClient registryClient =
RegistryClient.factory("localhost:5000", "busybox").newAllowHttp();
RegistryClient.factory("localhost:5000", "busybox").setAllowHttp(true).newRegistryClient();
V21ManifestTemplate manifestTemplate =
registryClient.pullManifest("latest", V21ManifestTemplate.class);

Expand All @@ -44,7 +44,7 @@ public void testPull_v21() throws IOException, RegistryException {
@Test
public void testPull_v22() throws IOException, RegistryException {
RegistryClient registryClient =
RegistryClient.factory("gcr.io", "distroless/java").newWithAuthorization(null);
RegistryClient.factory("gcr.io", "distroless/java").newRegistryClient();
ManifestTemplate manifestTemplate = registryClient.pullManifest("latest");

Assert.assertEquals(2, manifestTemplate.getSchemaVersion());
Expand All @@ -56,7 +56,9 @@ public void testPull_v22() throws IOException, RegistryException {
public void testPull_unknownManifest() throws RegistryException, IOException {
try {
RegistryClient registryClient =
RegistryClient.factory("localhost:5000", "busybox").newAllowHttp();
RegistryClient.factory("localhost:5000", "busybox")
.setAllowHttp(true)
.newRegistryClient();
registryClient.pullManifest("nonexistent-tag");
Assert.fail("Trying to pull nonexistent image should have errored");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,11 @@ public class ManifestPusherIntegrationTest {
@Test
public void testPush_missingBlobs() throws IOException, RegistryException {
RegistryClient registryClient =
RegistryClient.factory("gcr.io", "distroless/java").newWithAuthorization(null);
RegistryClient.factory("gcr.io", "distroless/java").newRegistryClient();
ManifestTemplate manifestTemplate = registryClient.pullManifest("latest");

registryClient = RegistryClient.factory("localhost:5000", "busybox").newAllowHttp();
registryClient =
RegistryClient.factory("localhost:5000", "busybox").setAllowHttp(true).newRegistryClient();
try {
registryClient.pushManifest((V22ManifestTemplate) manifestTemplate, "latest");
Assert.fail("Pushing manifest without its BLOBs should fail");
Expand Down Expand Up @@ -72,7 +73,9 @@ public void testPush() throws DigestException, IOException, RegistryException {

// Pushes the BLOBs.
RegistryClient registryClient =
RegistryClient.factory("localhost:5000", "testimage").newAllowHttp();
RegistryClient.factory("localhost:5000", "testimage")
.setAllowHttp(true)
.newRegistryClient();
Assert.assertFalse(registryClient.pushBlob(testLayerBlobDigest, testLayerBlob));
Assert.assertFalse(
registryClient.pushBlob(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,14 +69,13 @@ public ListenableFuture<CachedLayer> getFuture() {
public CachedLayer call() throws IOException, RegistryException {
try (Timer ignored =
new Timer(buildConfiguration.getBuildLogger(), String.format(DESCRIPTION, layerDigest))) {
RegistryClient.Factory registryClientFactory =
RegistryClient.factory(
buildConfiguration.getBaseImageRegistry(),
buildConfiguration.getBaseImageRepository());
RegistryClient registryClient =
buildConfiguration.getAllowHttp()
? registryClientFactory.newAllowHttp()
: registryClientFactory.newWithAuthorization(pullAuthorization);
RegistryClient.factory(
buildConfiguration.getBaseImageRegistry(),
buildConfiguration.getBaseImageRepository())
.setAllowHttp(buildConfiguration.getAllowHttp())
.setAuthorization(pullAuthorization)
.newRegistryClient();

// Checks if the layer already exists in the cache.
CachedLayer cachedLayer = new CacheReader(cache).getLayer(layerDigest);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@
import com.google.cloud.tools.jib.image.json.V21ManifestTemplate;
import com.google.cloud.tools.jib.image.json.V22ManifestTemplate;
import com.google.cloud.tools.jib.json.JsonTemplateMapper;
import com.google.cloud.tools.jib.registry.RegistryAuthenticationFailedException;
import com.google.cloud.tools.jib.registry.RegistryAuthenticator;
import com.google.cloud.tools.jib.registry.RegistryAuthenticators;
import com.google.cloud.tools.jib.registry.RegistryClient;
import com.google.cloud.tools.jib.registry.RegistryException;
import com.google.cloud.tools.jib.registry.RegistryUnauthorizedException;
Expand Down Expand Up @@ -94,7 +97,7 @@ public ListenableFuture<BaseImageWithAuthorization> getFuture() {
@Override
public BaseImageWithAuthorization call()
throws IOException, RegistryException, LayerPropertyNotFoundException,
LayerCountMismatchException, ExecutionException {
LayerCountMismatchException, ExecutionException, RegistryAuthenticationFailedException {
buildConfiguration
.getBuildLogger()
.lifecycle("Getting base image " + buildConfiguration.getBaseImageReference() + "...");
Expand All @@ -114,8 +117,31 @@ public BaseImageWithAuthorization call()

Authorization registryCredentials =
NonBlockingSteps.get(retrieveBaseRegistryCredentialsStep);
return new BaseImageWithAuthorization(
pullBaseImage(registryCredentials), registryCredentials);

try {
return new BaseImageWithAuthorization(
pullBaseImage(registryCredentials), registryCredentials);

} catch (RegistryUnauthorizedException registryUnauthorizedException) {
// The registry requires us to authenticate using the Docker Token Authentication.
// See https://docs.docker.com/registry/spec/auth/token
RegistryAuthenticator registryAuthenticator =
RegistryAuthenticators.forOther(
buildConfiguration.getBaseImageRegistry(),
buildConfiguration.getBaseImageRepository());
if (registryAuthenticator == null) {
buildConfiguration
.getBuildLogger()
.error(
"Failed to retrieve authentication challenge for registry that required token authentication");
throw registryUnauthorizedException;
}
registryCredentials =
registryAuthenticator.setAuthorization(registryCredentials).authenticatePull();

return new BaseImageWithAuthorization(
pullBaseImage(registryCredentials), registryCredentials);
}
}
}
}
Expand All @@ -134,13 +160,13 @@ public BaseImageWithAuthorization call()
private Image<Layer> pullBaseImage(@Nullable Authorization registryCredentials)
throws IOException, RegistryException, LayerPropertyNotFoundException,
LayerCountMismatchException {
RegistryClient.Factory registryClientFactory =
RegistryClient.factory(
buildConfiguration.getBaseImageRegistry(), buildConfiguration.getBaseImageRepository());
RegistryClient registryClient =
buildConfiguration.getAllowHttp()
? registryClientFactory.newAllowHttp()
: registryClientFactory.newWithAuthorization(registryCredentials);
RegistryClient.factory(
buildConfiguration.getBaseImageRegistry(),
buildConfiguration.getBaseImageRepository())
.setAllowHttp(buildConfiguration.getAllowHttp())
.setAuthorization(registryCredentials)
.newRegistryClient();

ManifestTemplate manifestTemplate =
registryClient.pullManifest(buildConfiguration.getBaseImageTag());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,15 +68,13 @@ public ListenableFuture<BlobDescriptor> getFuture() {
public BlobDescriptor call() throws IOException, RegistryException, ExecutionException {
try (Timer timer =
new Timer(buildConfiguration.getBuildLogger(), DESCRIPTION + blobDescriptor)) {
RegistryClient.Factory registryClientFactory =
RegistryClient.factory(
buildConfiguration.getTargetImageRegistry(),
buildConfiguration.getTargetImageRepository());
RegistryClient registryClient =
buildConfiguration.getAllowHttp()
? registryClientFactory.newAllowHttp()
: registryClientFactory.newWithAuthorization(
NonBlockingSteps.get(authenticatePushStep));
RegistryClient.factory(
buildConfiguration.getTargetImageRegistry(),
buildConfiguration.getTargetImageRepository())
.setAllowHttp(buildConfiguration.getAllowHttp())
.setAuthorization(NonBlockingSteps.get(authenticatePushStep))
.newRegistryClient();
registryClient.setTimer(timer);

if (registryClient.checkBlob(blobDescriptor.getDigest()) != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,15 +116,13 @@ private ListenableFuture<Void> afterPushSteps() throws ExecutionException {

private Void afterAllPushed() throws IOException, RegistryException, ExecutionException {
try (Timer ignored = new Timer(buildConfiguration.getBuildLogger(), DESCRIPTION)) {
RegistryClient.Factory registryClientFactory =
RegistryClient.factory(
buildConfiguration.getTargetImageRegistry(),
buildConfiguration.getTargetImageRepository());
RegistryClient registryClient =
buildConfiguration.getAllowHttp()
? registryClientFactory.newAllowHttp()
: registryClientFactory.newWithAuthorization(
NonBlockingSteps.get(authenticatePushStep));
RegistryClient.factory(
buildConfiguration.getTargetImageRegistry(),
buildConfiguration.getTargetImageRepository())
.setAllowHttp(buildConfiguration.getAllowHttp())
.setAuthorization(NonBlockingSteps.get(authenticatePushStep))
.newRegistryClient();

// Constructs the image.
ImageToJsonTranslator imageToJsonTranslator =
Expand Down
Loading

0 comments on commit d735f70

Please sign in to comment.