Skip to content

Commit

Permalink
Cache results of auth lookups (testcontainers#2213)
Browse files Browse the repository at this point in the history
  • Loading branch information
rnorth committed Apr 4, 2020
1 parent 08e13bf commit 7eced8b
Showing 1 changed file with 22 additions and 9 deletions.
Expand Up @@ -16,6 +16,8 @@
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

Expand All @@ -38,6 +40,8 @@ public class RegistryAuthLocator {
private final String commandExtension;
private final File configFile;

private final Map<String, Optional<AuthConfig>> cache = new ConcurrentHashMap<>();

/**
* key - credential helper's name
* value - helper's response for "credentials not found" use case
Expand Down Expand Up @@ -97,47 +101,56 @@ static void setInstance(RegistryAuthLocator overrideInstance) {
* @return an AuthConfig that is applicable to this specific image OR the defaultAuthConfig.
*/
public AuthConfig lookupAuthConfig(DockerImageName dockerImageName, AuthConfig defaultAuthConfig) {
final String registryName = effectiveRegistryName(dockerImageName);
log.debug("Looking up auth config for image: {} at registry: {}", dockerImageName, registryName);

final Optional<AuthConfig> cachedAuth = cache.computeIfAbsent(registryName, __ -> lookupUncachedAuthConfig(registryName, dockerImageName));

log.debug("Looking up auth config for image: {}", dockerImageName);
if (cachedAuth.isPresent()) {
log.debug("Cached auth found: [{}]", toSafeString(cachedAuth.get()));
return cachedAuth.get();
} else {
log.debug("No matching Auth Configs - falling back to defaultAuthConfig [{}]", toSafeString(defaultAuthConfig));
// otherwise, defaultAuthConfig should already contain any credentials available
return defaultAuthConfig;
}
}

private Optional<AuthConfig> lookupUncachedAuthConfig(String registryName, DockerImageName dockerImageName) {
log.debug("RegistryAuthLocator has configFile: {} ({}) and commandPathPrefix: {}",
configFile,
configFile.exists() ? "exists" : "does not exist",
commandPathPrefix);

try {
final JsonNode config = OBJECT_MAPPER.readTree(configFile);
final String registryName = effectiveRegistryName(dockerImageName);
log.debug("registryName [{}] for dockerImageName [{}]", registryName, dockerImageName);

// use helper preferentially (per https://docs.docker.com/engine/reference/commandline/cli/)
final AuthConfig helperAuthConfig = authConfigUsingHelper(config, registryName);
if (helperAuthConfig != null) {
log.debug("found helper auth config [{}]", toSafeString(helperAuthConfig));
return helperAuthConfig;
return Optional.of(helperAuthConfig);
}
// no credsHelper to use, using credsStore:
final AuthConfig storeAuthConfig = authConfigUsingStore(config, registryName);
if (storeAuthConfig != null) {
log.debug("found creds store auth config [{}]", toSafeString(storeAuthConfig));
return storeAuthConfig;
return Optional.of(storeAuthConfig);
}
// fall back to base64 encoded auth hardcoded in config file
final AuthConfig existingAuthConfig = findExistingAuthConfig(config, registryName);
if (existingAuthConfig != null) {
log.debug("found existing auth config [{}]", toSafeString(existingAuthConfig));
return existingAuthConfig;
return Optional.of(existingAuthConfig);
}

log.debug("no matching Auth Configs - falling back to defaultAuthConfig [{}]", toSafeString(defaultAuthConfig));
// otherwise, defaultAuthConfig should already contain any credentials available
} catch (Exception e) {
log.warn("Failure when attempting to lookup auth config (dockerImageName: {}, configFile: {}. Falling back to docker-java default behaviour. Exception message: {}",
dockerImageName,
configFile,
e.getMessage());
}
return defaultAuthConfig;
return Optional.empty();
}

private AuthConfig findExistingAuthConfig(final JsonNode config, final String reposName) throws Exception {
Expand Down

0 comments on commit 7eced8b

Please sign in to comment.