diff --git a/src/main/java/com/github/dockerjava/api/model/AuthConfig.java b/src/main/java/com/github/dockerjava/api/model/AuthConfig.java index d7f0deab3..87307bb5d 100644 --- a/src/main/java/com/github/dockerjava/api/model/AuthConfig.java +++ b/src/main/java/com/github/dockerjava/api/model/AuthConfig.java @@ -1,5 +1,6 @@ package com.github.dockerjava.api.model; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; public class AuthConfig { @@ -23,6 +24,8 @@ public class AuthConfig { @JsonProperty("serveraddress") private String serverAddress = DEFAULT_SERVER_ADDRESS; + private String auth; + public String getUsername() { return username; } @@ -55,6 +58,16 @@ public void setServerAddress(String serverAddress) { this.serverAddress = serverAddress; } + @JsonIgnore + public String getAuth() { + return auth; + } + + @JsonProperty("auth") + public void setAuth(String auth) { + this.auth = auth; + } + @Override public String toString() { return "AuthConfig{" + @@ -64,4 +77,53 @@ public String toString() { ", serverAddress='" + serverAddress + '\'' + '}'; } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((auth == null) ? 0 : auth.hashCode()); + result = prime * result + ((email == null) ? 0 : email.hashCode()); + result = prime * result + ((password == null) ? 0 : password.hashCode()); + result = prime * result + ((serverAddress == null) ? 0 : serverAddress.hashCode()); + result = prime * result + ((username == null) ? 0 : username.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + AuthConfig other = (AuthConfig) obj; + if (auth == null) { + if (other.auth != null) + return false; + } else if (!auth.equals(other.auth)) + return false; + if (email == null) { + if (other.email != null) + return false; + } else if (!email.equals(other.email)) + return false; + if (password == null) { + if (other.password != null) + return false; + } else if (!password.equals(other.password)) + return false; + if (serverAddress == null) { + if (other.serverAddress != null) + return false; + } else if (!serverAddress.equals(other.serverAddress)) + return false; + if (username == null) { + if (other.username != null) + return false; + } else if (!username.equals(other.username)) + return false; + return true; + } } diff --git a/src/main/java/com/github/dockerjava/core/AuthConfigFile.java b/src/main/java/com/github/dockerjava/core/AuthConfigFile.java new file mode 100644 index 000000000..24c7aa5cf --- /dev/null +++ b/src/main/java/com/github/dockerjava/core/AuthConfigFile.java @@ -0,0 +1,146 @@ +package com.github.dockerjava.core; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.Charset; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.io.FileUtils; +import org.apache.commons.lang.StringUtils; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.dockerjava.api.model.AuthConfig; + +public class AuthConfigFile { + private static final ObjectMapper MAPPER = new ObjectMapper(); + private static final TypeReference> CONFIG_MAP_TYPE = new TypeReference>() {}; + private final Map authConfigMap; + + public AuthConfigFile() { + authConfigMap = new HashMap(); + } + + void addConfig(AuthConfig config) { + authConfigMap.put(config.getServerAddress(), config); + } + + public AuthConfig resolveAuthConfig(String hostname) { + if (StringUtils.isEmpty(hostname) || AuthConfig.DEFAULT_SERVER_ADDRESS.equals(hostname)) { + return authConfigMap.get(AuthConfig.DEFAULT_SERVER_ADDRESS); + } + AuthConfig c = authConfigMap.get(hostname); + if (c != null) { + return c; + } + + // Maybe they have a legacy config file, we will iterate the keys converting + // them to the new format and testing + String normalizedHostname = convertToHostname(hostname); + for (Map.Entry entry : authConfigMap.entrySet()) { + String registry = entry.getKey(); + AuthConfig config = entry.getValue(); + if (convertToHostname(registry).equals(normalizedHostname)) { + return config; + } + } + return null; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((authConfigMap == null) ? 0 : authConfigMap.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + AuthConfigFile other = (AuthConfigFile) obj; + if (authConfigMap == null) { + if (other.authConfigMap != null) + return false; + } else if (!authConfigMap.equals(other.authConfigMap)) + return false; + return true; + } + + @Override + public String toString() { + return "AuthConfigFile [authConfigMap=" + authConfigMap + "]"; + } + + + public static AuthConfigFile loadConfig(File confFile) throws IOException { + AuthConfigFile configFile = new AuthConfigFile(); + if (!confFile.exists()) { + return new AuthConfigFile(); + } + Map configMap = null; + try { + configMap = MAPPER.readValue(confFile, CONFIG_MAP_TYPE); + } catch (IOException e) { + // pass + } + if (configMap != null) { + for (Map.Entry entry : configMap.entrySet()) { + AuthConfig authConfig = entry.getValue(); + decodeAuth(authConfig.getAuth(), authConfig); + authConfig.setAuth(null); + authConfig.setServerAddress(entry.getKey()); + configFile.addConfig(authConfig); + } + } else { + List authFileContent = FileUtils.readLines(confFile); + if (authFileContent.size() < 2) { + throw new IOException("The Auth Config file is empty"); + } + AuthConfig config = new AuthConfig(); + String[] origAuth = authFileContent.get(0).split(" = "); + if (origAuth.length != 2) { + throw new IOException("Invalid Auth config file"); + } + decodeAuth(origAuth[1], config); + + String[] origEmail = authFileContent.get(1).split(" = "); + if (origEmail.length != 2) { + throw new IOException("Invalid Auth config file"); + } + config.setEmail(origEmail[1]); + configFile.addConfig(config); + } + return configFile; + + } + + static void decodeAuth(String auth, AuthConfig config) throws IOException { + String str = new String(Base64.decodeBase64(auth), Charset.forName("UTF-8")); + String[] parts = str.split(":", 2); + if (parts.length != 2) { + throw new IOException("Invalid auth configuration file"); + } + config.setUsername(parts[0]); + config.setPassword(parts[1]); + } + + static String convertToHostname(String server) { + String stripped = server; + if (server.startsWith("http://")) { + stripped = server.substring(7); + } else if (server.startsWith("https://")) { + stripped = server.substring(8); + } + String[] numParts = stripped.split("/", 2); + return numParts[0]; + } +} diff --git a/src/main/java/com/github/dockerjava/core/DockerClientConfig.java b/src/main/java/com/github/dockerjava/core/DockerClientConfig.java index 9f1694b5e..ff1329c69 100644 --- a/src/main/java/com/github/dockerjava/core/DockerClientConfig.java +++ b/src/main/java/com/github/dockerjava/core/DockerClientConfig.java @@ -23,6 +23,7 @@ public class DockerClientConfig { // this is really confusing, as there are two ways to spell it private static final String DOCKER_IO_ENABLE_LOGGING_FILTER_PROPERTY = "docker.io.enableLoggingFilter"; private static final String DOCKER_IO_DOCKER_CERT_PATH_PROPERTY = "docker.io.dockerCertPath"; + private static final String DOCKER_IO_DOCKER_CFG_PATH_PROPERTY = "docker.io.dockerCfgPath"; /** * A map from the environment name to the interval name. */ @@ -36,14 +37,15 @@ public class DockerClientConfig { .put("DOCKER_READ_TIMEOUT", DOCKER_IO_READ_TIMEOUT_PROPERTY) .put("DOCKER_LOGGING_FILTER_ENABLED", DOCKER_IO_ENABLE_LOGGING_FILTER_PROPERTY) .put(DOCKER_CERT_PATH_PROPERTY, DOCKER_IO_DOCKER_CERT_PATH_PROPERTY) + .put("DOCKER_CFG_PATH", DOCKER_IO_DOCKER_CFG_PATH_PROPERTY) .build(); private static final String DOCKER_IO_PROPERTIES_PROPERTY = "docker.io.properties"; private final URI uri; - private final String version, username, password, email, serverAddress, dockerCertPath; + private final String version, username, password, email, serverAddress, dockerCertPath, dockerCfgPath; private final Integer readTimeout; private final boolean loggingFilterEnabled; - DockerClientConfig(URI uri, String version, String username, String password, String email, String serverAddress, String dockerCertPath, Integer readTimeout, boolean loggingFilterEnabled) { + DockerClientConfig(URI uri, String version, String username, String password, String email, String serverAddress, String dockerCertPath, String dockerCfgPath, Integer readTimeout, boolean loggingFilterEnabled) { this.uri = uri; this.version = version; this.username = username; @@ -51,6 +53,7 @@ public class DockerClientConfig { this.email = email; this.serverAddress = serverAddress; this.dockerCertPath = dockerCertPath; + this.dockerCfgPath = dockerCfgPath; this.readTimeout = readTimeout; this.loggingFilterEnabled = loggingFilterEnabled; } @@ -153,6 +156,7 @@ private static Properties overrideDockerPropertiesWithSystemProperties(Propertie DOCKER_IO_READ_TIMEOUT_PROPERTY, DOCKER_IO_ENABLE_LOGGING_FILTER_PROPERTY, DOCKER_IO_DOCKER_CERT_PATH_PROPERTY, + DOCKER_IO_DOCKER_CFG_PATH_PROPERTY, }) { if (systemProperties.containsKey(key)) { overriddenProperties.setProperty(key, systemProperties.getProperty(key)); @@ -212,6 +216,10 @@ public String getDockerCertPath() { return dockerCertPath; } + public String getDockerCfgPath() { + return dockerCfgPath; + } + @Override public boolean equals(Object o) { if (this == o) return true; @@ -222,6 +230,8 @@ public boolean equals(Object o) { if (loggingFilterEnabled != that.loggingFilterEnabled) return false; if (dockerCertPath != null ? !dockerCertPath.equals(that.dockerCertPath) : that.dockerCertPath != null) return false; + if (dockerCfgPath != null ? !dockerCfgPath.equals(that.dockerCfgPath) : that.dockerCfgPath != null) + return false; if (email != null ? !email.equals(that.email) : that.email != null) return false; if (password != null ? !password.equals(that.password) : that.password != null) return false; if (readTimeout != null ? !readTimeout.equals(that.readTimeout) : that.readTimeout != null) return false; @@ -243,6 +253,7 @@ public int hashCode() { result = 31 * result + (email != null ? email.hashCode() : 0); result = 31 * result + (serverAddress != null ? serverAddress.hashCode() : 0); result = 31 * result + (dockerCertPath != null ? dockerCertPath.hashCode() : 0); + result = 31 * result + (dockerCfgPath != null ? dockerCfgPath.hashCode() : 0); result = 31 * result + (readTimeout != null ? readTimeout.hashCode() : 0); result = 31 * result + (loggingFilterEnabled ? 1 : 0); return result; @@ -258,6 +269,7 @@ public String toString() { ", email='" + email + '\'' + ", serverAddress='" + serverAddress + '\'' + ", dockerCertPath='" + dockerCertPath + '\'' + + ", dockerCfgPath='" + dockerCfgPath + '\'' + ", readTimeout=" + readTimeout + ", loggingFilterEnabled=" + loggingFilterEnabled + '}'; @@ -265,15 +277,15 @@ public String toString() { public static class DockerClientConfigBuilder { private URI uri; - private String version, username, password, email, serverAddress, dockerCertPath; + private String version, username, password, email, serverAddress, dockerCertPath, dockerCfgPath; private Integer readTimeout; private boolean loggingFilterEnabled; /** * This will set all fields in the builder to those contained in the Properties object. The Properties object - * should contain the following docker.io.* keys: url, version, username, password, email, and dockerCertPath. If - * docker.io.readTimeout or docker.io.enableLoggingFilter are not contained, they will be set to 1000 and true, - * respectively. + * should contain the following docker.io.* keys: url, version, username, password, email, dockerCertPath, and + * dockerCfgPath. If docker.io.readTimeout or docker.io.enableLoggingFilter are not contained, they will be set + * to 1000 and true, respectively. */ public DockerClientConfigBuilder withProperties(Properties p) { return withUri(p.getProperty(DOCKER_IO_URL_PROPERTY)) @@ -284,7 +296,8 @@ public DockerClientConfigBuilder withProperties(Properties p) { .withServerAddress(p.getProperty(DOCKER_IO_SERVER_ADDRESS_PROPERTY)) .withReadTimeout(Integer.valueOf(p.getProperty(DOCKER_IO_READ_TIMEOUT_PROPERTY, "0"))) .withLoggingFilter(Boolean.valueOf(p.getProperty(DOCKER_IO_ENABLE_LOGGING_FILTER_PROPERTY, "true"))) - .withDockerCertPath(p.getProperty(DOCKER_IO_DOCKER_CERT_PATH_PROPERTY)); + .withDockerCertPath(p.getProperty(DOCKER_IO_DOCKER_CERT_PATH_PROPERTY)) + .withDockerCfgPath(p.getProperty(DOCKER_IO_DOCKER_CFG_PATH_PROPERTY)); } public final DockerClientConfigBuilder withUri(String uri) { @@ -333,6 +346,12 @@ public final DockerClientConfigBuilder withDockerCertPath(String dockerCertPath) return this; } + public final DockerClientConfigBuilder withDockerCfgPath(String dockerCfgPath) { + this.dockerCfgPath = dockerCfgPath; + return this; + } + + public DockerClientConfig build() { return new DockerClientConfig( uri, @@ -342,6 +361,7 @@ public DockerClientConfig build() { email, serverAddress, dockerCertPath, + dockerCfgPath, readTimeout, loggingFilterEnabled ); diff --git a/src/main/java/com/github/dockerjava/core/DockerClientImpl.java b/src/main/java/com/github/dockerjava/core/DockerClientImpl.java index 2630d26d4..1a2a58c0b 100644 --- a/src/main/java/com/github/dockerjava/core/DockerClientImpl.java +++ b/src/main/java/com/github/dockerjava/core/DockerClientImpl.java @@ -8,21 +8,24 @@ import java.io.InputStream; import com.github.dockerjava.api.DockerClient; +import com.github.dockerjava.api.DockerClientException; import com.github.dockerjava.api.command.*; import com.github.dockerjava.api.model.AuthConfig; +import com.github.dockerjava.core.NameParser.HostnameReposName; +import com.github.dockerjava.core.NameParser.ReposTag; import com.github.dockerjava.core.command.*; import com.google.common.base.Preconditions; /** * @author Konstantin Pelykh (kpelykh@gmail.com) - * + * * @see https://github.com/docker/docker/blob/master/api/client/commands.go */ public class DockerClientImpl implements Closeable, DockerClient { private final DockerClientConfig dockerClientConfig; - - private DockerCmdExecFactory dockerCmdExecFactory; + + private DockerCmdExecFactory dockerCmdExecFactory; private DockerClientImpl() { this(DockerClientConfig.createDefaultConfigBuilder().build()); @@ -36,25 +39,25 @@ private DockerClientImpl(DockerClientConfig dockerClientConfig) { Preconditions.checkNotNull(dockerClientConfig, "config was not specified"); this.dockerClientConfig = dockerClientConfig; } - + private static DockerClientConfig configWithServerUrl(String serverUrl) { return DockerClientConfig.createDefaultConfigBuilder() .withUri(serverUrl) .build(); } - + public static DockerClientImpl getInstance() { return new DockerClientImpl(); } - + public static DockerClientImpl getInstance(DockerClientConfig dockerClientConfig) { return new DockerClientImpl(dockerClientConfig); } - + public static DockerClientImpl getInstance(String serverUrl) { return new DockerClientImpl(serverUrl); } - + public DockerClientImpl withDockerCmdExecFactory( DockerCmdExecFactory dockerCmdExecFactory) { Preconditions.checkNotNull(dockerCmdExecFactory, "dockerCmdExecFactory was not specified"); @@ -62,13 +65,14 @@ public DockerClientImpl withDockerCmdExecFactory( this.dockerCmdExecFactory.init(dockerClientConfig); return this; } - + private DockerCmdExecFactory getDockerCmdExecFactory() { Preconditions.checkNotNull(dockerCmdExecFactory, "dockerCmdExecFactory was not specified"); return dockerCmdExecFactory; } - + + @Override public AuthConfig authConfig() { checkNotNull(dockerClientConfig.getUsername(), "Configured username is null."); checkNotNull(dockerClientConfig.getServerAddress(), "Configured serverAddress is null."); @@ -92,7 +96,7 @@ public AuthConfig authConfig() { @Override public AuthCmd authCmd() { return new AuthCmdImpl(getDockerCmdExecFactory().createAuthCmdExec(), authConfig()); - } + } @Override public InfoCmd infoCmd() { @@ -102,7 +106,7 @@ public InfoCmd infoCmd() { @Override public PingCmd pingCmd() { return new PingCmdImpl(getDockerCmdExecFactory().createPingCmdExec()); - } + } @Override public VersionCmd versionCmd() { @@ -120,7 +124,24 @@ public PullImageCmd pullImageCmd(String repository) { @Override public PushImageCmd pushImageCmd(String name) { - return new PushImageCmdImpl(getDockerCmdExecFactory().createPushImageCmdExec(), name); + PushImageCmd cmd = new PushImageCmdImpl(getDockerCmdExecFactory().createPushImageCmdExec(), + name); + String dockerCfgFile = dockerClientConfig.getDockerCfgPath(); + if (dockerCfgFile != null) { + AuthConfigFile authConfigFile; + try { + authConfigFile = AuthConfigFile.loadConfig(new File(dockerCfgFile)); + } catch (IOException e) { + throw new DockerClientException("Failed to parse dockerCfgFile", e); + } + ReposTag reposTag = NameParser.parseRepositoryTag(name); + HostnameReposName hostnameReposName = NameParser.resolveRepositoryName(reposTag.repos); + AuthConfig authConfig = authConfigFile.resolveAuthConfig(hostnameReposName.hostname); + if (authConfig != null) { + cmd.withAuthConfig(authConfig); + } + } + return cmd; } @Override @@ -132,7 +153,7 @@ public CreateImageCmd createImageCmd(String repository, InputStream imageStream) public SearchImagesCmd searchImagesCmd(String term) { return new SearchImagesCmdImpl(getDockerCmdExecFactory().createSearchImagesCmdExec(), term); } - + @Override public RemoveImageCmd removeImageCmd(String imageId) { return new RemoveImageCmdImpl(getDockerCmdExecFactory().createRemoveImageCmdExec(), imageId); @@ -171,7 +192,7 @@ public StartContainerCmd startContainerCmd(String containerId) { public InspectContainerCmd inspectContainerCmd(String containerId) { return new InspectContainerCmdImpl(getDockerCmdExecFactory().createInspectContainerCmdExec(), containerId); } - + @Override public RemoveContainerCmd removeContainerCmd(String containerId) { return new RemoveContainerCmdImpl(getDockerCmdExecFactory().createRemoveContainerCmdExec(), containerId); @@ -196,7 +217,7 @@ public LogContainerCmd logContainerCmd(String containerId) { public CopyFileFromContainerCmd copyFileFromContainerCmd(String containerId, String resource) { return new CopyFileFromContainerCmdImpl(getDockerCmdExecFactory().createCopyFileFromContainerCmdExec(), containerId, resource); } - + @Override public ContainerDiffCmd containerDiffCmd(String containerId) { return new ContainerDiffCmdImpl(getDockerCmdExecFactory().createContainerDiffCmdExec(), containerId); @@ -206,7 +227,7 @@ public ContainerDiffCmd containerDiffCmd(String containerId) { public StopContainerCmd stopContainerCmd(String containerId) { return new StopContainerCmdImpl(getDockerCmdExecFactory().createStopContainerCmdExec(), containerId); } - + @Override public KillContainerCmd killContainerCmd(String containerId) { return new KillContainerCmdImpl(getDockerCmdExecFactory().createKillContainerCmdExec(), containerId); @@ -246,7 +267,7 @@ public TagImageCmd tagImageCmd(String imageId, String repository, String tag) { public PauseContainerCmd pauseContainerCmd(String containerId) { return new PauseContainerCmdImpl(getDockerCmdExecFactory().createPauseContainerCmdExec(), containerId); } - + @Override public UnpauseContainerCmd unpauseContainerCmd(String containerId) { return new UnpauseContainerCmdImpl(getDockerCmdExecFactory().createUnpauseContainerCmdExec(), containerId); diff --git a/src/main/java/com/github/dockerjava/core/InvalidRepositoryNameException.java b/src/main/java/com/github/dockerjava/core/InvalidRepositoryNameException.java new file mode 100644 index 000000000..8885fc756 --- /dev/null +++ b/src/main/java/com/github/dockerjava/core/InvalidRepositoryNameException.java @@ -0,0 +1,15 @@ +package com.github.dockerjava.core; + +public class InvalidRepositoryNameException extends IllegalArgumentException { + + private static final long serialVersionUID = -6908709623436840513L; + + public InvalidRepositoryNameException() { + super(); + } + + public InvalidRepositoryNameException(String s) { + super(s); + } + +} diff --git a/src/main/java/com/github/dockerjava/core/NameParser.java b/src/main/java/com/github/dockerjava/core/NameParser.java new file mode 100644 index 000000000..6b1654081 --- /dev/null +++ b/src/main/java/com/github/dockerjava/core/NameParser.java @@ -0,0 +1,100 @@ +/** + * Copyright (C) 2014 SignalFuse, Inc. + */ +package com.github.dockerjava.core; + +import java.util.regex.Pattern; + +import com.github.dockerjava.api.model.AuthConfig; + +public class NameParser { + + private static final Pattern VALID_HEX_PATTERN = Pattern.compile("^([a-f0-9]{64})$"); + private static final Pattern VALID_NAMESPACE_PATTERN = Pattern.compile("^([a-z0-9_]{4,30})$"); + private static final Pattern VALID_REPO_PATTERN = Pattern.compile("^([a-z0-9-_.]+)$"); + + public static ReposTag parseRepositoryTag(String name) { + int n = name.lastIndexOf(':'); + if (n < 0) { + return new ReposTag(name, ""); + } + String tag = name.substring(n + 1); + if (!tag.contains("/")) { + return new ReposTag(name.substring(0, n), tag); + } + return new ReposTag(name, ""); + } + + public static class ReposTag { + public final String repos; + public final String tag; + + public ReposTag(String repos, String tag) { + this.repos = repos; + this.tag = tag; + } + } + + public static void validateRepositoryName(String repositoryName) { + String name; + String namespace; + String[] nameParts = repositoryName.split("/", 2); + if (nameParts.length < 2) { + namespace = "library"; + name = nameParts[0]; + if (VALID_HEX_PATTERN.matcher(name).matches()) { + throw new InvalidRepositoryNameException(String.format( + "Invalid repository name (%s), cannot specify 64-byte hexadecimal strings", + name)); + } + } else { + namespace = nameParts[0]; + name = nameParts[1]; + } + if (!VALID_NAMESPACE_PATTERN.matcher(namespace).matches()) { + throw new InvalidRepositoryNameException( + String.format( + "Invalid namespace name (%s), only [a-z0-9_] are allowed, size between 4 and 30", + namespace)); + } + if (!VALID_REPO_PATTERN.matcher(name).matches()) { + throw new InvalidRepositoryNameException(String.format( + "Invalid repository name (%s), only [a-z0-9-_.] are allowed", name)); + } + } + + public static HostnameReposName resolveRepositoryName(String reposName) { + if (reposName.contains("://")) { + // It cannot contain a scheme! + throw new InvalidRepositoryNameException(); + } + + String[] nameParts = reposName.split("/", 2); + if (nameParts.length == 1 + || (!nameParts[0].contains(".") && !nameParts[0].contains(":") && !nameParts[0] + .equals("localhost"))) { + return new HostnameReposName(AuthConfig.DEFAULT_SERVER_ADDRESS, reposName); + } + + String hostname = nameParts[0]; + reposName = nameParts[1]; + if (hostname.contains("index.docker.io")) { + throw new InvalidRepositoryNameException(String.format( + "Invalid repository name, try \"%s\" instead", reposName)); + } + + validateRepositoryName(reposName); + return new HostnameReposName(hostname, reposName); + } + + public static class HostnameReposName { + public final String hostname; + public final String reposName; + + public HostnameReposName(String hostname, String reposName) { + this.hostname = hostname; + this.reposName = reposName; + } + + } +} diff --git a/src/main/resources/docker.io.properties b/src/main/resources/docker.io.properties index 2188cff37..6f0bfc86c 100644 --- a/src/main/resources/docker.io.properties +++ b/src/main/resources/docker.io.properties @@ -1,5 +1,6 @@ docker.io.url=https://localhost:2376 docker.io.enableLoggingFilter=true docker.io.dockerCertPath=${user.home}/.docker +docker.io.dockerCfgPath=${user.home}/.dockercfg docker.io.username=${user.name} docker.io.serverAddress=https://index.docker.io/v1/ \ No newline at end of file diff --git a/src/test/java/com/github/dockerjava/core/AuthConfigFileTest.java b/src/test/java/com/github/dockerjava/core/AuthConfigFileTest.java new file mode 100644 index 000000000..e1c1b6f8d --- /dev/null +++ b/src/test/java/com/github/dockerjava/core/AuthConfigFileTest.java @@ -0,0 +1,95 @@ +/** + * Copyright (C) 2014 SignalFuse, Inc. + */ +package com.github.dockerjava.core; + +import java.io.File; +import java.io.IOException; + +import org.testng.Assert; +import org.testng.annotations.Test; + +import com.github.dockerjava.api.model.AuthConfig; + +public class AuthConfigFileTest { + + private final File FILESROOT = new File(Thread.currentThread().getContextClassLoader() + .getResource("testAuthConfigFile").getFile()); + + @Test(expectedExceptions = IOException.class, expectedExceptionsMessageRegExp = "The Auth Config file is empty") + public void emptyFile() throws IOException { + runTest("emptyFile"); + } + + @Test(expectedExceptions = IOException.class, expectedExceptionsMessageRegExp = "The Auth Config file is empty") + public void tooSmallFile() throws IOException { + runTest("tooSmallFile"); + } + + @Test(expectedExceptions = IOException.class, expectedExceptionsMessageRegExp = "Invalid auth configuration file") + public void invalidJsonInvalidAuth() throws IOException { + runTest("invalidJsonInvalidAuth"); + } + + @Test(expectedExceptions = IOException.class, expectedExceptionsMessageRegExp = "Invalid Auth config file") + public void invalidLegacyAuthLine() throws IOException { + runTest("invalidLegacyAuthLine"); + } + + @Test(expectedExceptions = IOException.class, expectedExceptionsMessageRegExp = "Invalid auth configuration file") + public void invalidLegacyInvalidAuth() throws IOException { + runTest("invalidLegacyInvalidAuth"); + } + + @Test(expectedExceptions = IOException.class, expectedExceptionsMessageRegExp = "Invalid Auth config file") + public void invalidLegacyEmailLine() throws IOException { + runTest("invalidLegacyEmailLine"); + } + + @Test + public void validJson() throws IOException { + AuthConfig authConfig1 = new AuthConfig(); + authConfig1.setEmail("foo@example.com"); + authConfig1.setUsername("foo"); + authConfig1.setPassword("bar"); + authConfig1.setServerAddress("quay.io"); + + AuthConfig authConfig2 = new AuthConfig(); + authConfig2.setEmail("moo@example.com"); + authConfig2.setUsername("foo1"); + authConfig2.setPassword("bar1"); + authConfig2.setServerAddress(AuthConfig.DEFAULT_SERVER_ADDRESS); + + AuthConfigFile expected = new AuthConfigFile(); + expected.addConfig(authConfig1); + expected.addConfig(authConfig2); + + Assert.assertEquals(runTest("validJson"), expected); + + } + + @Test + public void validLegacy() throws IOException { + AuthConfig authConfig = new AuthConfig(); + authConfig.setEmail("foo@example.com"); + authConfig.setUsername("foo"); + authConfig.setPassword("bar"); + authConfig.setServerAddress(AuthConfig.DEFAULT_SERVER_ADDRESS); + + AuthConfigFile expected = new AuthConfigFile(); + expected.addConfig(authConfig); + + Assert.assertEquals(runTest("validLegacy"), expected); + } + + @Test + public void nonExistent() throws IOException { + AuthConfigFile expected = new AuthConfigFile(); + Assert.assertEquals(runTest("idontexist"), expected); + } + + private AuthConfigFile runTest(String testFileName) throws IOException { + return AuthConfigFile.loadConfig(new File(FILESROOT, testFileName)); + } + +} diff --git a/src/test/java/com/github/dockerjava/core/DockerClientConfigTest.java b/src/test/java/com/github/dockerjava/core/DockerClientConfigTest.java index f14640b07..06bb1ea12 100644 --- a/src/test/java/com/github/dockerjava/core/DockerClientConfigTest.java +++ b/src/test/java/com/github/dockerjava/core/DockerClientConfigTest.java @@ -16,12 +16,12 @@ public class DockerClientConfigTest { public static final DockerClientConfig EXAMPLE_CONFIG = newExampleConfig(); private static DockerClientConfig newExampleConfig() { - return new DockerClientConfig(URI.create("http://foo"), "bar", "baz", "qux", "blam", "wham", "flim", 877, false); + return new DockerClientConfig(URI.create("http://foo"), "bar", "baz", "qux", "blam", "wham", "flim", "flam", 877, false); } @Test public void string() throws Exception { - assertEquals("DockerClientConfig{uri=http://foo, version='bar', username='baz', password='qux', email='blam', serverAddress='wham', dockerCertPath='flim', readTimeout=877, loggingFilterEnabled=false}", + assertEquals("DockerClientConfig{uri=http://foo, version='bar', username='baz', password='qux', email='blam', serverAddress='wham', dockerCertPath='flim', dockerCfgPath='flam', readTimeout=877, loggingFilterEnabled=false}", EXAMPLE_CONFIG.toString()); } @@ -72,6 +72,7 @@ public void environment() throws Exception { env.put("DOCKER_EMAIL", "blam"); env.put("DOCKER_SERVER_ADDRESS", "wham"); env.put("DOCKER_CERT_PATH", "flim"); + env.put("DOCKER_CFG_PATH", "flam"); env.put("DOCKER_READ_TIMEOUT", "877"); env.put("DOCKER_LOGGING_FILTER_ENABLED", "false"); @@ -104,6 +105,7 @@ public void defaults() throws Exception { assertEquals(config.getVersion(), null); assertEquals(config.isLoggingFilterEnabled(), true); assertEquals(config.getDockerCertPath(), "someHomeDir/.docker"); + assertEquals(config.getDockerCfgPath(), "someHomeDir/.dockercfg"); } @Test @@ -118,6 +120,7 @@ public void systemProperties() throws Exception { systemProperties.setProperty("docker.io.email", "blam"); systemProperties.setProperty("docker.io.serverAddress", "wham"); systemProperties.setProperty("docker.io.dockerCertPath", "flim"); + systemProperties.setProperty("docker.io.dockerCfgPath", "flam"); systemProperties.setProperty("docker.io.readTimeout", "877"); systemProperties.setProperty("docker.io.enableLoggingFilter", "false"); diff --git a/src/test/java/com/github/dockerjava/core/DockerClientImplTest.java b/src/test/java/com/github/dockerjava/core/DockerClientImplTest.java index da1d7f8e4..c31db1ba9 100644 --- a/src/test/java/com/github/dockerjava/core/DockerClientImplTest.java +++ b/src/test/java/com/github/dockerjava/core/DockerClientImplTest.java @@ -10,7 +10,7 @@ public class DockerClientImplTest { @Test public void configuredInstanceAuthConfig() throws Exception { // given a config with null serverAddress - DockerClientConfig dockerClientConfig = new DockerClientConfig(null, null, "", "", "", null, null, 0, false); + DockerClientConfig dockerClientConfig = new DockerClientConfig(null, null, "", "", "", null, null, null, 0, false); DockerClientImpl dockerClient = DockerClientImpl.getInstance(dockerClientConfig); // when we get the auth config diff --git a/src/test/resources/testAuthConfigFile/emptyFile b/src/test/resources/testAuthConfigFile/emptyFile new file mode 100644 index 000000000..e69de29bb diff --git a/src/test/resources/testAuthConfigFile/invalidJsonInvalidAuth b/src/test/resources/testAuthConfigFile/invalidJsonInvalidAuth new file mode 100644 index 000000000..d0863065e --- /dev/null +++ b/src/test/resources/testAuthConfigFile/invalidJsonInvalidAuth @@ -0,0 +1 @@ +{"quay.io" : { "auth" : "Zm9vOmJhcg==", "email" :"foo@example.com"}, "https://index.docker.io/v1/" : {"auth" : "bW9vbzEyMw==", "email" : "moo@example.com"}} \ No newline at end of file diff --git a/src/test/resources/testAuthConfigFile/invalidLegacyAuthLine b/src/test/resources/testAuthConfigFile/invalidLegacyAuthLine new file mode 100644 index 000000000..7cbca287b --- /dev/null +++ b/src/test/resources/testAuthConfigFile/invalidLegacyAuthLine @@ -0,0 +1,2 @@ +auth =Zm9vOmJhcg== +email = foo@example.com \ No newline at end of file diff --git a/src/test/resources/testAuthConfigFile/invalidLegacyEmailLine b/src/test/resources/testAuthConfigFile/invalidLegacyEmailLine new file mode 100644 index 000000000..72d157b13 --- /dev/null +++ b/src/test/resources/testAuthConfigFile/invalidLegacyEmailLine @@ -0,0 +1,2 @@ +auth = Zm9vOmJhcg== +email =foo@example.com \ No newline at end of file diff --git a/src/test/resources/testAuthConfigFile/invalidLegacyInvalidAuth b/src/test/resources/testAuthConfigFile/invalidLegacyInvalidAuth new file mode 100644 index 000000000..d0af331a2 --- /dev/null +++ b/src/test/resources/testAuthConfigFile/invalidLegacyInvalidAuth @@ -0,0 +1,2 @@ +auth = bW9vbzEyMw== +email = foo@example.com \ No newline at end of file diff --git a/src/test/resources/testAuthConfigFile/tooSmallFile b/src/test/resources/testAuthConfigFile/tooSmallFile new file mode 100644 index 000000000..abf1731a2 --- /dev/null +++ b/src/test/resources/testAuthConfigFile/tooSmallFile @@ -0,0 +1 @@ +auth = Zm9vOmJhcg== \ No newline at end of file diff --git a/src/test/resources/testAuthConfigFile/validJson b/src/test/resources/testAuthConfigFile/validJson new file mode 100644 index 000000000..2b47e3822 --- /dev/null +++ b/src/test/resources/testAuthConfigFile/validJson @@ -0,0 +1 @@ +{"quay.io" : { "auth" : "Zm9vOmJhcg==", "email" :"foo@example.com"}, "https://index.docker.io/v1/" : {"auth" : "Zm9vMTpiYXIx", "email" : "moo@example.com"}} \ No newline at end of file diff --git a/src/test/resources/testAuthConfigFile/validLegacy b/src/test/resources/testAuthConfigFile/validLegacy new file mode 100644 index 000000000..9d4e740de --- /dev/null +++ b/src/test/resources/testAuthConfigFile/validLegacy @@ -0,0 +1,2 @@ +auth = Zm9vOmJhcg== +email = foo@example.com \ No newline at end of file