Skip to content

Commit

Permalink
Check other potential alises if Docker Hub
Browse files Browse the repository at this point in the history
  • Loading branch information
chanseokoh committed Jul 13, 2018
1 parent 5efd9ea commit 1432513
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,19 @@
import com.google.cloud.tools.jib.builder.BuildLogger;
import com.google.cloud.tools.jib.http.Authorization;
import com.google.cloud.tools.jib.registry.credentials.DockerConfigCredentialRetriever;
import com.google.cloud.tools.jib.registry.credentials.DockerCredentialHelperFactory;
import com.google.cloud.tools.jib.registry.credentials.DockerCredentialHelper;
import com.google.cloud.tools.jib.registry.credentials.NonexistentDockerCredentialHelperException;
import com.google.cloud.tools.jib.registry.credentials.NonexistentServerUrlDockerCredentialHelperException;
import com.google.cloud.tools.jib.registry.credentials.RegistryCredentials;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import java.io.IOException;
import java.util.concurrent.Callable;
import java.util.function.BiFunction;
import java.util.function.Function;
import javax.annotation.Nullable;

/** Attempts to retrieve registry credentials. */
Expand All @@ -46,6 +49,9 @@ class RetrieveRegistryCredentialsStep implements AsyncStep<Authorization>, Calla
private static final ImmutableMap<String, String> COMMON_CREDENTIAL_HELPERS =
ImmutableMap.of("gcr.io", "gcr", "amazonaws.com", "ecr-login");

private static final ImmutableList<String> DOCKER_HUB_REGISTRIES =
ImmutableList.of("registry.hub.docker.com", "index.docker.io");

/** Retrieves credentials for the base image. */
static RetrieveRegistryCredentialsStep forBaseImage(
ListeningExecutorService listeningExecutorService, BuildConfiguration buildConfiguration) {
Expand All @@ -72,8 +78,8 @@ static RetrieveRegistryCredentialsStep forTargetImage(
private final String registry;
@Nullable private final String credentialHelperSuffix;
@Nullable private final RegistryCredentials knownRegistryCredentials;
private final DockerCredentialHelperFactory dockerCredentialHelperFactory;
private final DockerConfigCredentialRetriever dockerConfigCredentialRetriever;
private final BiFunction<String, String, DockerCredentialHelper> dockerCredentialHelperFactory;
private final Function<String, DockerConfigCredentialRetriever> dockerConfigCredentialRetrieverFactory;

private final ListenableFuture<Authorization> listenableFuture;

Expand All @@ -84,14 +90,14 @@ static RetrieveRegistryCredentialsStep forTargetImage(
String registry,
@Nullable String credentialHelperSuffix,
@Nullable RegistryCredentials knownRegistryCredentials,
DockerCredentialHelperFactory dockerCredentialHelperFactory,
DockerConfigCredentialRetriever dockerConfigCredentialRetriever) {
BiFunction<String, String, DockerCredentialHelper> dockerCredentialHelperFactory,
Function<String, DockerConfigCredentialRetriever> dockerConfigCredentialRetrieverFactory) {
this.buildLogger = buildLogger;
this.registry = registry;
this.credentialHelperSuffix = credentialHelperSuffix;
this.knownRegistryCredentials = knownRegistryCredentials;
this.dockerCredentialHelperFactory = dockerCredentialHelperFactory;
this.dockerConfigCredentialRetriever = dockerConfigCredentialRetriever;
this.dockerConfigCredentialRetrieverFactory = dockerConfigCredentialRetrieverFactory;

listenableFuture = listeningExecutorService.submit(this);
}
Expand All @@ -109,8 +115,8 @@ private RetrieveRegistryCredentialsStep(
registry,
credentialHelperSuffix,
knownRegistryCredentials,
new DockerCredentialHelperFactory(registry),
new DockerConfigCredentialRetriever(registry));
DockerCredentialHelper::new,
DockerConfigCredentialRetriever::new);
}

@Override
Expand All @@ -121,6 +127,17 @@ public ListenableFuture<Authorization> getFuture() {
@Override
@Nullable
public Authorization call() throws IOException, NonexistentDockerCredentialHelperException {
Authorization authorization = getAuthorization(registry);

if (authorization == null && isDockerHubRegistry(registry)) {
buildLogger.info("Registry is Docker Hub. Checking if credentials for other Docker Hub alises are configured.");
return findOtherDockerHubCredential(registry);
}
return authorization;
}

private Authorization getAuthorization(String registry)
throws IOException, NonexistentDockerCredentialHelperException {
buildLogger.lifecycle(String.format(DESCRIPTION, registry) + "...");

try (Timer ignored = new Timer(buildLogger, String.format(DESCRIPTION, registry))) {
Expand Down Expand Up @@ -163,7 +180,7 @@ public Authorization call() throws IOException, NonexistentDockerCredentialHelpe

// Tries to get registry credentials from the Docker config.
try {
Authorization dockerConfigAuthorization = dockerConfigCredentialRetriever.retrieve();
Authorization dockerConfigAuthorization = dockerConfigCredentialRetrieverFactory.apply(registry).retrieve();
if (dockerConfigAuthorization != null) {
buildLogger.info("Using credentials from Docker config for " + registry);
return dockerConfigAuthorization;
Expand All @@ -178,10 +195,30 @@ public Authorization call() throws IOException, NonexistentDockerCredentialHelpe
* public and does not need extra credentials) and return null.
*/
buildLogger.info("No credentials could be retrieved for registry " + registry);

return null;
}
}

@VisibleForTesting
static boolean isDockerHubRegistry(String registry) {
return DOCKER_HUB_REGISTRIES.stream().anyMatch(registry::equals);
}

@VisibleForTesting
Authorization findOtherDockerHubCredential(String dockerHubRegistry)
throws IOException, NonexistentDockerCredentialHelperException {
for (String otherRegistry : DOCKER_HUB_REGISTRIES) {
if (!otherRegistry.equals(dockerHubRegistry)) {
Authorization authorization = getAuthorization(otherRegistry);
if (authorization != null) {
return authorization;
}
}
}
return null;
}

/**
* Attempts to retrieve authorization for the registry using {@code
* docker-credential-[credentialHelperSuffix]}.
Expand All @@ -194,9 +231,7 @@ Authorization retrieveFromCredentialHelper(String credentialHelperSuffix)

try {
Authorization authorization =
dockerCredentialHelperFactory
.withCredentialHelperSuffix(credentialHelperSuffix)
.retrieve();
dockerCredentialHelperFactory.apply(registry, credentialHelperSuffix).retrieve();
logGotCredentialsFrom("docker-credential-" + credentialHelperSuffix);
return authorization;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,10 @@ private static class DockerCredentialsTemplate implements JsonTemplate {
}

/**
* Construct with {@link DockerCredentialHelperFactory}.
*
* @param serverUrl the server URL to pass into the credential helper
* @param credentialHelperSuffix the credential helper CLI suffix
*/
DockerCredentialHelper(String serverUrl, String credentialHelperSuffix) {
public DockerCredentialHelper(String serverUrl, String credentialHelperSuffix) {
this.serverUrl = serverUrl;
this.credentialHelperSuffix = credentialHelperSuffix;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@
import com.google.cloud.tools.jib.http.Authorization;
import com.google.cloud.tools.jib.registry.credentials.DockerConfigCredentialRetriever;
import com.google.cloud.tools.jib.registry.credentials.DockerCredentialHelper;
import com.google.cloud.tools.jib.registry.credentials.DockerCredentialHelperFactory;
import com.google.cloud.tools.jib.registry.credentials.NonexistentDockerCredentialHelperException;
import com.google.cloud.tools.jib.registry.credentials.NonexistentServerUrlDockerCredentialHelperException;
import com.google.cloud.tools.jib.registry.credentials.RegistryCredentials;
import com.google.common.util.concurrent.ListeningExecutorService;
import java.io.IOException;
import java.util.function.BiFunction;
import javax.annotation.Nullable;
import org.junit.Assert;
import org.junit.Before;
Expand All @@ -46,7 +46,7 @@ public class RetrieveRegistryCredentialsStepTest {
@Mock private BuildConfiguration mockBuildConfiguration;
@Mock private BuildLogger mockBuildLogger;

@Mock private DockerCredentialHelperFactory mockDockerCredentialHelperFactory;
@Mock private BiFunction<String, String, DockerCredentialHelper> mockDockerCredentialHelperFactory;
@Mock private DockerCredentialHelper mockDockerCredentialHelper;
/**
* A {@link DockerCredentialHelper} that throws {@link
Expand Down Expand Up @@ -84,9 +84,7 @@ public void setUpMocks()
@Test
public void testCall_useCredentialHelper()
throws IOException, NonexistentDockerCredentialHelperException {
Mockito.when(
mockDockerCredentialHelperFactory.withCredentialHelperSuffix(
"someOtherCredentialHelper"))
Mockito.when(mockDockerCredentialHelperFactory.apply(FAKE_TARGET_REGISTRY, "someOtherCredentialHelper"))
.thenReturn(mockDockerCredentialHelper);

Assert.assertEquals(
Expand Down Expand Up @@ -116,8 +114,7 @@ public void testCall_useKnownRegistryCredentials()
public void testCall_useDockerConfig()
throws IOException, NonexistentDockerCredentialHelperException {
// Credential helper does not have credentials.
Mockito.when(
mockDockerCredentialHelperFactory.withCredentialHelperSuffix("someCredentialHelper"))
Mockito.when(mockDockerCredentialHelperFactory.apply(FAKE_TARGET_REGISTRY, "someCredentialHelper"))
.thenReturn(mockNonexistentServerUrlDockerCredentialHelper);

Mockito.when(mockDockerConfigCredentialRetriever.retrieve()).thenReturn(mockAuthorization);
Expand All @@ -134,9 +131,9 @@ public void testCall_useDockerConfig()
@Test
public void testCall_inferCommonCredentialHelpers()
throws IOException, NonexistentDockerCredentialHelperException {
Mockito.when(mockDockerCredentialHelperFactory.withCredentialHelperSuffix("gcr"))
Mockito.when(mockDockerCredentialHelperFactory.apply("something.gcr.io", "gcr"))
.thenReturn(mockDockerCredentialHelper);
Mockito.when(mockDockerCredentialHelperFactory.withCredentialHelperSuffix("ecr-login"))
Mockito.when(mockDockerCredentialHelperFactory.apply("something.amazonaws.com", "ecr-login"))
.thenReturn(mockNonexistentDockerCredentialHelper);

Assert.assertEquals(
Expand All @@ -150,6 +147,21 @@ public void testCall_inferCommonCredentialHelpers()
Mockito.verify(mockBuildLogger).warn("warning");
}

@Test
public void testIsDockerHubRegistry_registryHubDockerCom() {
Assert.assertTrue(RetrieveRegistryCredentialsStep.isDockerHubRegistry("registry.hub.docker.com"));
}

@Test
public void testIsDockerHubRegistry_indexDockerIo() {
Assert.assertTrue(RetrieveRegistryCredentialsStep.isDockerHubRegistry("index.docker.io"));
}

@Test
public void testIsDockerHubRegistry_nonDockerHub() {
Assert.assertFalse(RetrieveRegistryCredentialsStep.isDockerHubRegistry("something.gcr.io"));
}

/** Creates a fake {@link RetrieveRegistryCredentialsStep} for {@code registry}. */
private RetrieveRegistryCredentialsStep makeRetrieveRegistryCredentialsStep(
String registry,
Expand All @@ -164,6 +176,6 @@ private RetrieveRegistryCredentialsStep makeRetrieveRegistryCredentialsStep(
credentialHelperSuffix,
knownRegistryCredentials,
mockDockerCredentialHelperFactory,
mockDockerConfigCredentialRetriever);
ignored -> mockDockerConfigCredentialRetriever);
}
}

0 comments on commit 1432513

Please sign in to comment.