Skip to content

Commit 2edfcb0

Browse files
author
Marcus Linke
committed
Polish binding for port ranges
1 parent 12b986d commit 2edfcb0

File tree

10 files changed

+119
-93
lines changed

10 files changed

+119
-93
lines changed

src/main/java/com/github/dockerjava/api/model/Ports.java

Lines changed: 60 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -107,69 +107,85 @@ public Map<ExposedPort, Binding[]> getBindings() {
107107
// return bindings.toArray(new PortBinding[bindings.size()]);
108108
// }
109109

110-
/**
111-
* Creates a {@link Binding} for the given IP address and port number.
112-
*/
113-
public static Binding binding(String hostIp, String hostPort) {
114-
return new Binding(hostIp, hostPort);
115-
}
116-
117-
/**
118-
* Creates a {@link Binding} for the given port number, leaving the IP address undefined.
119-
*/
120-
public static Binding binding(String hostPort) {
121-
return new Binding(null, hostPort);
122-
}
123-
124110
/**
125111
* A {@link Binding} represents a socket on the Docker host that is used in a {@link PortBinding}. It is characterized by an
126-
* {@link #getHostIp() IP address} and a {@link #getHostPort() port number}. Both properties may be <code>null</code> in order to let
127-
* Docker assign them dynamically/using defaults.
112+
* {@link #getHostIp() IP address} and a {@link #getHostPortSpec() port spec}. Both properties may be <code>null</code> in order to
113+
* let Docker assign them dynamically/using defaults.
128114
*
129115
* @see Ports#bind(ExposedPort, Binding)
130116
* @see ExposedPort
131117
*/
132118
public static class Binding {
133119

134120
/**
135-
* Creates a {@link Binding} for the given {@link #getHostPort() port number or range}, leaving the {@link #getHostIp() IP address}
121+
* Creates a {@link Binding} for the given {@link #getHostPortSpec() port spec}, leaving the {@link #getHostIp() IP address}
136122
* undefined.
137123
*
138124
* @see Ports#bind(ExposedPort, Binding)
139125
* @see ExposedPort
140126
*/
141-
public static Binding forPort(String port) {
142-
return new Binding(null, port);
127+
public static Binding bindPortSpec(String portSpec) {
128+
return new Binding(null, portSpec);
143129
}
144130

145131
/**
146-
* Creates a {@link Binding} for the given {@link #getHostIp() IP address}, leaving the {@link #getHostPort() port number}
132+
* Creates a {@link Binding} for the given {@link #getHostIp() IP address}, leaving the {@link #getHostPortSpec() port spec}
147133
* undefined.
148134
*/
149-
public static Binding forIp(String hostIp) {
135+
public static Binding bindIp(String hostIp) {
150136
return new Binding(hostIp, null);
151137
}
152138

139+
/**
140+
* Creates a {@link Binding} for the given {@link #getHostIp() IP address} and port number.
141+
*/
142+
public static Binding bindIpAndPort(String hostIp, int port) {
143+
return new Binding(hostIp, "" + port);
144+
}
145+
146+
/**
147+
* Creates a {@link Binding} for the given {@link #getHostIp() IP address} and port range.
148+
*/
149+
public static Binding bindIpAndPortRange(String hostIp, int lowPort, int highPort) {
150+
return new Binding(hostIp, lowPort + "-" + highPort);
151+
}
152+
153+
/**
154+
* Creates a {@link Binding} for the given port range, leaving the {@link #getHostIp() IP address}
155+
* undefined.
156+
*/
157+
public static Binding bindPortRange(int lowPort, int highPort) {
158+
return bindIpAndPortRange(null, lowPort, highPort);
159+
}
160+
161+
/**
162+
* Creates a {@link Binding} for the given port leaving the {@link #getHostIp() IP address}
163+
* undefined.
164+
*/
165+
public static Binding bindPort(int port) {
166+
return bindIpAndPort(null, port);
167+
}
168+
169+
/**
170+
* Creates an empty {@link Binding}.
171+
*/
172+
public static Binding empty() {
173+
return new Binding(null, null);
174+
}
175+
153176
private final String hostIp;
154177

155-
private final String hostPort;
178+
private final String hostPortSpec;
156179

157180
/**
158-
* Creates a {@link Binding} for the given {@link #getHostIp() IP address} and {@link #getHostPort() port number}.
181+
* Creates a {@link Binding} for the given {@link #getHostIp() host IP address} and {@link #getHostPortSpec() host port spec}.
159182
*
160183
* @see Ports#bind(ExposedPort, Binding)
161184
* @see ExposedPort
162185
*/
163-
public Binding(String hostIp, String hostPort) {
186+
public Binding(String hostIp, String hostPortSpec) {
164187
this.hostIp = isEmpty(hostIp) ? null : hostIp;
165-
this.hostPort = hostPort;
166-
}
167-
168-
/**
169-
* Creates a {@link Binding} with both {@link #getHostIp() IP address} and {@link #getHostPort() port number} undefined.
170-
*/
171-
public Binding() {
172-
this(null, null);
188+
this.hostPortSpec = hostPortSpec;
173189
}
174190

175191
/**
@@ -181,16 +197,17 @@ public String getHostIp() {
181197
}
182198

183199
/**
184-
* @return the port number on the Docker host. May be <code>null</code>, in which case Docker will dynamically assign a port.
200+
* @return the port spec for the binding on the Docker host. May reference a single port ("1234"), a port range ("1234-2345") or
201+
* <code>null</code>, in which case Docker will dynamically assign a port.
185202
*/
186-
public String getHostPort() {
187-
return hostPort;
203+
public String getHostPortSpec() {
204+
return hostPortSpec;
188205
}
189206

190207
/**
191208
* Parses a textual host and port specification (as used by the Docker CLI) to a {@link Binding}.
192209
* <p>
193-
* Legal syntax: <code>IP|IP:port|port</code>
210+
* Legal syntax: <code>IP|IP:portSpec|portSpec</code> where <code>portSpec</code> is either a single port or a port range
194211
*
195212
* @param serialized
196213
* serialized the specification, e.g. <code>127.0.0.1:80</code>
@@ -201,7 +218,7 @@ public String getHostPort() {
201218
public static Binding parse(String serialized) throws IllegalArgumentException {
202219
try {
203220
if (serialized.isEmpty()) {
204-
return new Binding();
221+
return Binding.empty();
205222
}
206223

207224
String[] parts = serialized.split(":");
@@ -210,7 +227,7 @@ public static Binding parse(String serialized) throws IllegalArgumentException {
210227
return new Binding(parts[0], parts[1]);
211228
}
212229
case 1: {
213-
return parts[0].contains(".") ? Binding.forIp(parts[0]) : Binding.forPort(parts[0]);
230+
return parts[0].contains(".") ? Binding.bindIp(parts[0]) : Binding.bindPortSpec(parts[0]);
214231
}
215232
default: {
216233
throw new IllegalArgumentException();
@@ -230,19 +247,19 @@ public static Binding parse(String serialized) throws IllegalArgumentException {
230247
@Override
231248
public String toString() {
232249
if (isEmpty(hostIp)) {
233-
return hostPort;
234-
} else if (hostPort == null) {
250+
return hostPortSpec;
251+
} else if (hostPortSpec == null) {
235252
return hostIp;
236253
} else {
237-
return hostIp + ":" + hostPort;
254+
return hostIp + ":" + hostPortSpec;
238255
}
239256
}
240257

241258
@Override
242259
public boolean equals(Object obj) {
243260
if (obj instanceof Binding) {
244261
Binding other = (Binding) obj;
245-
return new EqualsBuilder().append(hostIp, other.getHostIp()).append(hostPort, other.getHostPort())
262+
return new EqualsBuilder().append(hostIp, other.getHostIp()).append(hostPortSpec, other.getHostPortSpec())
246263
.isEquals();
247264
} else {
248265
return super.equals(obj);
@@ -293,7 +310,7 @@ public void serialize(Ports portBindings, JsonGenerator jsonGen, SerializerProvi
293310
for (Binding binding : entry.getValue()) {
294311
jsonGen.writeStartObject();
295312
jsonGen.writeStringField("HostIp", binding.getHostIp() == null ? "" : binding.getHostIp());
296-
jsonGen.writeStringField("HostPort", binding.getHostPort() == null ? "" : binding.getHostPort());
313+
jsonGen.writeStringField("HostPort", binding.getHostPortSpec() == null ? "" : binding.getHostPortSpec());
297314
jsonGen.writeEndObject();
298315
}
299316
jsonGen.writeEndArray();

src/test/java/com/github/dockerjava/api/model/BindingTest.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,22 @@ public class BindingTest {
1010

1111
@Test
1212
public void parseIpAndPort() {
13-
assertEquals(Binding.parse("127.0.0.1:80"), Ports.binding("127.0.0.1", "80"));
13+
assertEquals(Binding.parse("127.0.0.1:80"), Binding.bindIpAndPort("127.0.0.1", 80));
1414
}
1515

1616
@Test
1717
public void parsePortOnly() {
18-
assertEquals(Binding.parse("80"), Ports.binding(null, "80"));
18+
assertEquals(Binding.parse("80"), Binding.bindPort(80));
1919
}
2020

2121
@Test
2222
public void parseIPOnly() {
23-
assertEquals(Binding.parse("127.0.0.1"), Ports.binding("127.0.0.1", null));
23+
assertEquals(Binding.parse("127.0.0.1"), Binding.bindIp("127.0.0.1"));
2424
}
2525

2626
@Test
2727
public void parseEmptyString() {
28-
assertEquals(Binding.parse(""), Ports.binding(null, null));
28+
assertEquals(Binding.parse(""), Binding.empty());
2929
}
3030

3131
// Strings can be used since it can be a range. Let the docker daemon do the validation.

src/test/java/com/github/dockerjava/api/model/PortBindingTest.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,32 +13,32 @@ public class PortBindingTest {
1313
@Test
1414
public void fullDefinition() {
1515
assertEquals(PortBinding.parse("127.0.0.1:80:8080/tcp"),
16-
new PortBinding(new Binding("127.0.0.1", "80"), TCP_8080));
16+
new PortBinding(Binding.bindIpAndPort("127.0.0.1", 80), TCP_8080));
1717
}
1818

1919
@Test
2020
public void noProtocol() {
21-
assertEquals(PortBinding.parse("127.0.0.1:80:8080"), new PortBinding(new Binding("127.0.0.1", "80"), TCP_8080));
21+
assertEquals(PortBinding.parse("127.0.0.1:80:8080"), new PortBinding(Binding.bindIpAndPort("127.0.0.1", 80), TCP_8080));
2222
}
2323

2424
@Test
2525
public void noHostIp() {
26-
assertEquals(PortBinding.parse("80:8080/tcp"), new PortBinding(Binding.forPort("80"), TCP_8080));
26+
assertEquals(PortBinding.parse("80:8080/tcp"), new PortBinding(Binding.bindPort(80), TCP_8080));
2727
}
2828

2929
@Test
3030
public void portsOnly() {
31-
assertEquals(PortBinding.parse("80:8080"), new PortBinding(Binding.forPort("80"), TCP_8080));
31+
assertEquals(PortBinding.parse("80:8080"), new PortBinding(Binding.bindPort(80), TCP_8080));
3232
}
3333

3434
@Test
3535
public void exposedPortOnly() {
36-
assertEquals(PortBinding.parse("8080"), new PortBinding(new Binding(), TCP_8080));
36+
assertEquals(PortBinding.parse("8080"), new PortBinding(Binding.empty(), TCP_8080));
3737
}
3838

3939
@Test
4040
public void dynamicHostPort() {
41-
assertEquals(PortBinding.parse("127.0.0.1::8080"), new PortBinding(Binding.forIp("127.0.0.1"), TCP_8080));
41+
assertEquals(PortBinding.parse("127.0.0.1::8080"), new PortBinding(Binding.bindIp("127.0.0.1"), TCP_8080));
4242
}
4343

4444
@Test(expectedExceptions = IllegalArgumentException.class, expectedExceptionsMessageRegExp = "Error parsing PortBinding 'nonsense'", enabled = false)

src/test/java/com/github/dockerjava/api/model/Ports_addBindingsTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ public class Ports_addBindingsTest {
1717

1818
private static final ExposedPort TCP_90 = ExposedPort.tcp(90);
1919

20-
private static final Binding BINDING_8080 = Ports.binding("8080");
20+
private static final Binding BINDING_8080 = Binding.bindPort(8080);
2121

22-
private static final Binding BINDING_9090 = Ports.binding("9090");
22+
private static final Binding BINDING_9090 = Binding.bindPort(9090);
2323

2424
private Ports ports;
2525

src/test/java/com/github/dockerjava/core/command/BuildImageCmdImplTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ public void testBuildFromPrivateRegistry() throws Exception {
263263
CreateContainerResponse testregistry = dockerClient
264264
.createContainerCmd("testregistry:2")
265265
.withName("registry")
266-
.withPortBindings(new PortBinding(Ports.Binding.forPort("5000"), ExposedPort.tcp(5000)))
266+
.withPortBindings(new PortBinding(Ports.Binding.bindPortSpec("5000"), ExposedPort.tcp(5000)))
267267
.withEnv("REGISTRY_AUTH=htpasswd", "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm",
268268
"REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd", "REGISTRY_LOG_LEVEL=debug",
269269
"REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt", "REGISTRY_HTTP_TLS_KEY=/certs/domain.key")

src/test/java/com/github/dockerjava/core/command/CreateContainerCmdImplTest.java

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@
1515
import com.github.dockerjava.api.model.Ulimit;
1616
import com.github.dockerjava.api.model.Volume;
1717
import com.github.dockerjava.api.model.VolumesFrom;
18+
import com.github.dockerjava.api.model.Ports.Binding;
1819
import com.github.dockerjava.client.AbstractDockerClientTest;
20+
1921
import org.testng.ITestResult;
2022
import org.testng.annotations.AfterMethod;
2123
import org.testng.annotations.AfterTest;
@@ -361,9 +363,9 @@ public void createContainerWithPortBindings() throws DockerException {
361363
ExposedPort tcp23 = ExposedPort.tcp(23);
362364

363365
Ports portBindings = new Ports();
364-
portBindings.bind(tcp22, Ports.binding("11022"));
365-
portBindings.bind(tcp23, Ports.binding("11023"));
366-
portBindings.bind(tcp23, Ports.binding("11024"));
366+
portBindings.bind(tcp22, Binding.bindPort(11022));
367+
portBindings.bind(tcp23, Binding.bindPort(11023));
368+
portBindings.bind(tcp23, Binding.bindPort(11024));
367369

368370
CreateContainerResponse container = dockerClient.createContainerCmd(BUSYBOX_IMAGE).withCmd("true")
369371
.withExposedPorts(tcp22, tcp23).withPortBindings(portBindings).exec();
@@ -377,13 +379,13 @@ public void createContainerWithPortBindings() throws DockerException {
377379
assertThat(Arrays.asList(inspectContainerResponse.getConfig().getExposedPorts()), contains(tcp22, tcp23));
378380

379381
assertThat(inspectContainerResponse.getHostConfig().getPortBindings().getBindings().get(tcp22)[0],
380-
is(equalTo(Ports.binding("11022"))));
382+
is(equalTo(Binding.bindPort(11022))));
381383

382384
assertThat(inspectContainerResponse.getHostConfig().getPortBindings().getBindings().get(tcp23)[0],
383-
is(equalTo(Ports.binding("11023"))));
385+
is(equalTo(Binding.bindPort(11023))));
384386

385387
assertThat(inspectContainerResponse.getHostConfig().getPortBindings().getBindings().get(tcp23)[1],
386-
is(equalTo(Ports.binding("11024"))));
388+
is(equalTo(Binding.bindPort(11024))));
387389

388390
}
389391

src/test/java/com/github/dockerjava/core/command/StartContainerCmdImplTest.java

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@
1515
import com.github.dockerjava.api.model.RestartPolicy;
1616
import com.github.dockerjava.api.model.Volume;
1717
import com.github.dockerjava.api.model.VolumesFrom;
18+
import com.github.dockerjava.api.model.Ports.Binding;
1819
import com.github.dockerjava.client.AbstractDockerClientTest;
20+
1921
import org.testng.ITestResult;
2022
import org.testng.annotations.AfterMethod;
2123
import org.testng.annotations.AfterTest;
@@ -188,9 +190,9 @@ public void startContainerWithPortBindings() throws DockerException {
188190
ExposedPort tcp23 = ExposedPort.tcp(23);
189191

190192
Ports portBindings = new Ports();
191-
portBindings.bind(tcp22, Ports.binding("11022"));
192-
portBindings.bind(tcp23, Ports.binding("11023"));
193-
portBindings.bind(tcp23, Ports.binding("11024"));
193+
portBindings.bind(tcp22, Binding.bindPort(11022));
194+
portBindings.bind(tcp23, Binding.bindPort(11023));
195+
portBindings.bind(tcp23, Binding.bindPort(11024));
194196

195197
CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withCmd("true")
196198
.withExposedPorts(tcp22, tcp23).withPortBindings(portBindings).exec();
@@ -208,13 +210,13 @@ public void startContainerWithPortBindings() throws DockerException {
208210
assertThat(Arrays.asList(inspectContainerResponse.getConfig().getExposedPorts()), contains(tcp22, tcp23));
209211

210212
assertThat(inspectContainerResponse.getHostConfig().getPortBindings().getBindings().get(tcp22)[0],
211-
is(equalTo(Ports.binding("11022"))));
213+
is(equalTo(Binding.bindPort(11022))));
212214

213215
assertThat(inspectContainerResponse.getHostConfig().getPortBindings().getBindings().get(tcp23)[0],
214-
is(equalTo(Ports.binding("11023"))));
216+
is(equalTo(Binding.bindPort(11023))));
215217

216218
assertThat(inspectContainerResponse.getHostConfig().getPortBindings().getBindings().get(tcp23)[1],
217-
is(equalTo(Ports.binding("11024"))));
219+
is(equalTo(Binding.bindPort(11024))));
218220

219221
}
220222

@@ -225,8 +227,8 @@ public void startContainerWithRandomPortBindings() throws DockerException {
225227
ExposedPort tcp23 = ExposedPort.tcp(23);
226228

227229
Ports portBindings = new Ports();
228-
portBindings.bind(tcp22, Ports.binding(null));
229-
portBindings.bind(tcp23, Ports.binding(null));
230+
portBindings.bind(tcp22, Binding.empty());
231+
portBindings.bind(tcp23, Binding.empty());
230232

231233
CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withCmd("sleep", "9999")
232234
.withExposedPorts(tcp22, tcp23).withPortBindings(portBindings).withPublishAllPorts(true).exec();
@@ -241,10 +243,10 @@ public void startContainerWithRandomPortBindings() throws DockerException {
241243

242244
assertThat(Arrays.asList(inspectContainerResponse.getConfig().getExposedPorts()), contains(tcp22, tcp23));
243245

244-
assertThat(inspectContainerResponse.getNetworkSettings().getPorts().getBindings().get(tcp22)[0].getHostPort(),
246+
assertThat(inspectContainerResponse.getNetworkSettings().getPorts().getBindings().get(tcp22)[0].getHostPortSpec(),
245247
is(not(equalTo(String.valueOf(tcp22.getPort())))));
246248

247-
assertThat(inspectContainerResponse.getNetworkSettings().getPorts().getBindings().get(tcp23)[0].getHostPort(),
249+
assertThat(inspectContainerResponse.getNetworkSettings().getPorts().getBindings().get(tcp23)[0].getHostPortSpec(),
248250
is(not(equalTo(String.valueOf(tcp23.getPort())))));
249251

250252
}
@@ -256,8 +258,8 @@ public void startContainerWithConflictingPortBindings() throws DockerException {
256258
ExposedPort tcp23 = ExposedPort.tcp(23);
257259

258260
Ports portBindings = new Ports();
259-
portBindings.bind(tcp22, Ports.binding("11022"));
260-
portBindings.bind(tcp23, Ports.binding("11022"));
261+
portBindings.bind(tcp22, Binding.bindPort(11022));
262+
portBindings.bind(tcp23, Binding.bindPort(11022));
261263

262264
CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withCmd("true")
263265
.withExposedPorts(tcp22, tcp23).withPortBindings(portBindings).exec();

0 commit comments

Comments
 (0)