Skip to content

Commit 1e13c89

Browse files
author
Marcus Thiesen
committed
Add API versioning support
An issue with docker-java currently is that API < 1.19 has a different authentication scheme than newer API versions. This leads to major problems in environments with different docker installations (see alexec/docker-java-orchestration#49) docker-java Issue #288 fixed the issue for API >= 1.19, but let older servers out of the consideration. This patch distributes the client config through the executors and thus allows the execution to vary depending on those options.
1 parent 3ebe8ca commit 1e13c89

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+533
-412
lines changed

src/main/java/com/github/dockerjava/core/DockerClientConfig.java

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
package com.github.dockerjava.core;
22

3-
import static com.google.common.base.Preconditions.checkNotNull;
3+
import com.github.dockerjava.api.DockerClientException;
4+
import com.github.dockerjava.api.model.AuthConfig;
5+
import com.github.dockerjava.api.model.AuthConfigurations;
6+
import com.github.dockerjava.core.NameParser.HostnameReposName;
7+
import com.github.dockerjava.core.NameParser.ReposTag;
48

59
import java.io.File;
610
import java.io.FileInputStream;
@@ -12,11 +16,7 @@
1216
import java.util.Map;
1317
import java.util.Properties;
1418

15-
import com.github.dockerjava.api.DockerClientException;
16-
import com.github.dockerjava.api.model.AuthConfig;
17-
import com.github.dockerjava.api.model.AuthConfigurations;
18-
import com.github.dockerjava.core.NameParser.HostnameReposName;
19-
import com.github.dockerjava.core.NameParser.ReposTag;
19+
import static com.google.common.base.Preconditions.checkNotNull;
2020

2121
public class DockerClientConfig implements Serializable {
2222

@@ -66,14 +66,16 @@ public class DockerClientConfig implements Serializable {
6666

6767
private URI uri;
6868

69-
private final String version, username, password, email, serverAddress, dockerCfgPath;
69+
private final String username, password, email, serverAddress, dockerCfgPath;
70+
71+
private final RemoteApiVersion version;
7072

7173
private final SSLConfig sslConfig;
7274

7375
DockerClientConfig(URI uri, String version, String username, String password, String email, String serverAddress,
7476
String dockerCfgPath, SSLConfig sslConfig) {
7577
this.uri = uri;
76-
this.version = version;
78+
this.version = RemoteApiVersion.parseConfigWithDefault(version);
7779
this.username = username;
7880
this.password = password;
7981
this.email = email;
@@ -209,7 +211,7 @@ public void setUri(URI uri) {
209211
this.uri = uri;
210212
}
211213

212-
public String getVersion() {
214+
public RemoteApiVersion getVersion() {
213215
return version;
214216
}
215217

src/main/java/com/github/dockerjava/core/DockerClientImpl.java

Lines changed: 12 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,5 @@
11
package com.github.dockerjava.core;
22

3-
import static com.google.common.base.Preconditions.checkNotNull;
4-
5-
import java.io.Closeable;
6-
import java.io.File;
7-
import java.io.IOException;
8-
import java.io.InputStream;
9-
103
import com.github.dockerjava.api.DockerClient;
114
import com.github.dockerjava.api.command.AttachContainerCmd;
125
import com.github.dockerjava.api.command.AuthCmd;
@@ -46,7 +39,6 @@
4639
import com.github.dockerjava.api.command.VersionCmd;
4740
import com.github.dockerjava.api.command.WaitContainerCmd;
4841
import com.github.dockerjava.api.model.AuthConfig;
49-
import com.github.dockerjava.api.model.AuthConfigurations;
5042
import com.github.dockerjava.api.model.Identifier;
5143
import com.github.dockerjava.core.command.AttachContainerCmdImpl;
5244
import com.github.dockerjava.core.command.AuthCmdImpl;
@@ -85,6 +77,13 @@
8577
import com.github.dockerjava.core.command.VersionCmdImpl;
8678
import com.github.dockerjava.core.command.WaitContainerCmdImpl;
8779

80+
import java.io.Closeable;
81+
import java.io.File;
82+
import java.io.IOException;
83+
import java.io.InputStream;
84+
85+
import static com.google.common.base.Preconditions.checkNotNull;
86+
8887
/**
8988
* @author Konstantin Pelykh (kpelykh@gmail.com)
9089
*
@@ -332,28 +331,19 @@ public CommitCmd commitCmd(String containerId) {
332331

333332
@Override
334333
public BuildImageCmd buildImageCmd() {
335-
return augmentBuildImageCmd(new BuildImageCmdImpl(getDockerCmdExecFactory().createBuildImageCmdExec()));
334+
return new BuildImageCmdImpl(getDockerCmdExecFactory().createBuildImageCmdExec());
336335
}
337336

338337
@Override
339338
public BuildImageCmd buildImageCmd(File dockerFileOrFolder) {
340-
return augmentBuildImageCmd(new BuildImageCmdImpl(getDockerCmdExecFactory().createBuildImageCmdExec(),
341-
dockerFileOrFolder));
339+
return new BuildImageCmdImpl(getDockerCmdExecFactory().createBuildImageCmdExec(),
340+
dockerFileOrFolder);
342341
}
343342

344343
@Override
345344
public BuildImageCmd buildImageCmd(InputStream tarInputStream) {
346-
return augmentBuildImageCmd(new BuildImageCmdImpl(getDockerCmdExecFactory().createBuildImageCmdExec(),
347-
tarInputStream));
348-
}
349-
350-
private BuildImageCmd augmentBuildImageCmd(BuildImageCmd buildImageCmd) {
351-
final AuthConfigurations authConfigurations = dockerClientConfig.getAuthConfigurations();
352-
if (!authConfigurations.getConfigs().isEmpty()) {
353-
buildImageCmd.withBuildAuthConfigs(authConfigurations);
354-
}
355-
356-
return buildImageCmd;
345+
return new BuildImageCmdImpl(getDockerCmdExecFactory().createBuildImageCmdExec(),
346+
tarInputStream);
357347
}
358348

359349
@Override
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
package com.github.dockerjava.core;
2+
3+
import com.google.common.base.MoreObjects;
4+
import com.google.common.base.Objects;
5+
import com.google.common.base.Preconditions;
6+
import com.google.common.base.Strings;
7+
8+
import java.util.regex.Matcher;
9+
import java.util.regex.Pattern;
10+
11+
/**
12+
* Bean to encapsulate the version of the Docker Remote API (REST API)
13+
* <p>
14+
* Contains the minor and major version of the API as well as operations to compare API versions.
15+
*
16+
* @author Marcus Thiesen
17+
*/
18+
public class RemoteApiVersion {
19+
20+
public static final RemoteApiVersion VERSION_1_19 = RemoteApiVersion.create(1, 19);
21+
private static final Pattern VERSION_REGEX = Pattern.compile("v?(\\d+)\\.(\\d+)");
22+
private static final RemoteApiVersion UNKNOWN_VERSION = new RemoteApiVersion(0, 0) {
23+
24+
@Override
25+
public boolean isGreaterOrEqual(final RemoteApiVersion other) {
26+
return false;
27+
}
28+
29+
@Override
30+
public String toString() {
31+
return MoreObjects.toStringHelper(this).addValue("UNKNOWN_VERSION").toString();
32+
}
33+
34+
@Override
35+
public String asWebPathPart() {
36+
return "";
37+
}
38+
};
39+
private final int major;
40+
private final int minor;
41+
private RemoteApiVersion(final int major, final int minor) {
42+
this.major = major;
43+
this.minor = minor;
44+
}
45+
46+
public static RemoteApiVersion create(final int major, final int minor) {
47+
Preconditions.checkArgument(major > 0, "Major version must be bigger than 0 but is " + major);
48+
Preconditions.checkArgument(minor > 0, "Minor version must be bigger than 0 but is " + minor);
49+
return new RemoteApiVersion(major, minor);
50+
}
51+
52+
public static RemoteApiVersion unknown() {
53+
return UNKNOWN_VERSION;
54+
}
55+
56+
public static RemoteApiVersion parseConfig(final String version) {
57+
Preconditions.checkArgument(version != null, "Version must not be null");
58+
final Matcher matcher = VERSION_REGEX.matcher(version);
59+
if (matcher.matches()) {
60+
return create(Integer.parseInt(matcher.group(1)), Integer.parseInt(matcher.group(2)));
61+
}
62+
throw new IllegalArgumentException(version + " can not be parsed");
63+
}
64+
65+
public static RemoteApiVersion parseConfigWithDefault(final String version) {
66+
if (Strings.isNullOrEmpty(version)) {
67+
return UNKNOWN_VERSION;
68+
}
69+
70+
try {
71+
return parseConfig(version);
72+
} catch (IllegalArgumentException e) {
73+
return UNKNOWN_VERSION;
74+
}
75+
}
76+
77+
public boolean isGreaterOrEqual(final RemoteApiVersion other) {
78+
if (major >= other.major) {
79+
if (minor >= other.minor) {
80+
return true;
81+
}
82+
}
83+
return false;
84+
}
85+
86+
@Override
87+
public boolean equals(final Object o) {
88+
if (this == o) return true;
89+
if (o == null || getClass() != o.getClass()) return false;
90+
final RemoteApiVersion that = (RemoteApiVersion) o;
91+
return Objects.equal(major, that.major) &&
92+
Objects.equal(minor, that.minor);
93+
}
94+
95+
@Override
96+
public int hashCode() {
97+
return Objects.hashCode(major, minor);
98+
}
99+
100+
@Override
101+
public String toString() {
102+
return MoreObjects.toStringHelper(this)
103+
.add("major", major)
104+
.add("minor", minor)
105+
.toString();
106+
}
107+
108+
public String asWebPathPart() {
109+
return "v" + major + "." + minor;
110+
}
111+
}

src/main/java/com/github/dockerjava/jaxrs/AbstrAsyncDockerCmdExec.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11
package com.github.dockerjava.jaxrs;
22

3-
import java.io.Closeable;
4-
import java.io.IOException;
5-
6-
import javax.ws.rs.client.WebTarget;
7-
83
import com.github.dockerjava.api.async.ResultCallback;
94
import com.github.dockerjava.api.command.AsyncDockerCmd;
105
import com.github.dockerjava.api.command.DockerCmdAsyncExec;
6+
import com.github.dockerjava.core.DockerClientConfig;
117
import com.github.dockerjava.jaxrs.async.AbstractCallbackNotifier;
128

9+
import javax.ws.rs.client.WebTarget;
10+
import java.io.Closeable;
11+
import java.io.IOException;
12+
1313
public abstract class AbstrAsyncDockerCmdExec<CMD_T extends AsyncDockerCmd<CMD_T, A_RES_T>, A_RES_T> extends
1414
AbstrDockerCmdExec implements DockerCmdAsyncExec<CMD_T, A_RES_T> {
1515

16-
public AbstrAsyncDockerCmdExec(WebTarget baseResource) {
17-
super(baseResource);
16+
public AbstrAsyncDockerCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) {
17+
super(baseResource, dockerClientConfig);
1818
}
1919

2020
@Override

src/main/java/com/github/dockerjava/jaxrs/AbstrDockerCmdExec.java

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,37 @@
11
package com.github.dockerjava.jaxrs;
22

3-
import static com.google.common.base.Preconditions.checkNotNull;
4-
5-
import java.io.IOException;
6-
7-
import javax.ws.rs.client.WebTarget;
8-
9-
import org.apache.commons.codec.binary.Base64;
10-
113
import com.fasterxml.jackson.databind.ObjectMapper;
124
import com.github.dockerjava.api.model.AuthConfig;
135
import com.github.dockerjava.api.model.AuthConfigurations;
6+
import com.github.dockerjava.core.DockerClientConfig;
7+
import com.github.dockerjava.core.RemoteApiVersion;
8+
import org.apache.commons.codec.binary.Base64;
9+
10+
import javax.ws.rs.client.WebTarget;
11+
import java.io.IOException;
12+
13+
import static com.google.common.base.Preconditions.checkNotNull;
1414

1515
public abstract class AbstrDockerCmdExec {
1616

17-
private WebTarget baseResource;
17+
private final DockerClientConfig dockerClientConfig;
18+
private final WebTarget baseResource;
1819

19-
public AbstrDockerCmdExec(WebTarget baseResource) {
20+
public AbstrDockerCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) {
2021
checkNotNull(baseResource, "baseResource was not specified");
22+
checkNotNull(dockerClientConfig, "dockerClientConfig was not specified");
2123
this.baseResource = baseResource;
24+
this.dockerClientConfig = dockerClientConfig;
2225
}
2326

2427
protected WebTarget getBaseResource() {
2528
return baseResource;
2629
}
2730

31+
protected AuthConfigurations getBuildAuthConfigs() {
32+
return dockerClientConfig.getAuthConfigurations();
33+
}
34+
2835
protected String registryAuth(AuthConfig authConfig) {
2936
try {
3037
return Base64.encodeBase64String(new ObjectMapper().writeValueAsString(authConfig).getBytes());
@@ -35,7 +42,13 @@ protected String registryAuth(AuthConfig authConfig) {
3542

3643
protected String registryConfigs(AuthConfigurations authConfigs) {
3744
try {
38-
String json = new ObjectMapper().writeValueAsString(authConfigs.getConfigs());
45+
final String json;
46+
if (dockerClientConfig.getVersion().isGreaterOrEqual(RemoteApiVersion.VERSION_1_19)) {
47+
json = new ObjectMapper().writeValueAsString(authConfigs.getConfigs());
48+
} else {
49+
json = new ObjectMapper().writeValueAsString(authConfigs);
50+
}
51+
3952
return Base64.encodeBase64String(json.getBytes());
4053
} catch (IOException e) {
4154
throw new RuntimeException(e);

src/main/java/com/github/dockerjava/jaxrs/AbstrSyncDockerCmdExec.java

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
11
package com.github.dockerjava.jaxrs;
22

3-
import java.io.IOException;
4-
5-
import javax.ws.rs.ProcessingException;
6-
import javax.ws.rs.client.WebTarget;
7-
83
import com.github.dockerjava.api.DockerException;
94
import com.github.dockerjava.api.command.DockerCmd;
105
import com.github.dockerjava.api.command.DockerCmdSyncExec;
6+
import com.github.dockerjava.core.DockerClientConfig;
7+
8+
import javax.ws.rs.ProcessingException;
9+
import javax.ws.rs.client.WebTarget;
1110

1211
public abstract class AbstrSyncDockerCmdExec<CMD_T extends DockerCmd<RES_T>, RES_T> extends AbstrDockerCmdExec
1312
implements DockerCmdSyncExec<CMD_T, RES_T> {
1413

15-
public AbstrSyncDockerCmdExec(WebTarget baseResource) {
16-
super(baseResource);
14+
public AbstrSyncDockerCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) {
15+
super(baseResource, dockerClientConfig);
1716
}
1817

1918
@Override

src/main/java/com/github/dockerjava/jaxrs/AttachContainerCmdExec.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,24 @@
11
package com.github.dockerjava.jaxrs;
22

3-
import javax.ws.rs.client.WebTarget;
4-
5-
import org.slf4j.Logger;
6-
import org.slf4j.LoggerFactory;
7-
83
import com.github.dockerjava.api.async.ResultCallback;
94
import com.github.dockerjava.api.command.AttachContainerCmd;
105
import com.github.dockerjava.api.model.Frame;
6+
import com.github.dockerjava.core.DockerClientConfig;
117
import com.github.dockerjava.core.async.FrameStreamProcessor;
128
import com.github.dockerjava.jaxrs.async.AbstractCallbackNotifier;
139
import com.github.dockerjava.jaxrs.async.POSTCallbackNotifier;
10+
import org.slf4j.Logger;
11+
import org.slf4j.LoggerFactory;
12+
13+
import javax.ws.rs.client.WebTarget;
1414

1515
public class AttachContainerCmdExec extends AbstrAsyncDockerCmdExec<AttachContainerCmd, Frame> implements
1616
AttachContainerCmd.Exec {
1717

1818
private static final Logger LOGGER = LoggerFactory.getLogger(AttachContainerCmdExec.class);
1919

20-
public AttachContainerCmdExec(WebTarget baseResource) {
21-
super(baseResource);
20+
public AttachContainerCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) {
21+
super(baseResource, dockerClientConfig);
2222
}
2323

2424
@Override

0 commit comments

Comments
 (0)