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

Cache results of auth lookups #2213

Merged
merged 1 commit into from Apr 4, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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