Skip to content

Commit ca376d6

Browse files
author
Marcus Linke
committed
Added stdin parameter to attach command api, implemented for netty
1 parent a1c7bf5 commit ca376d6

10 files changed

Lines changed: 109 additions & 18 deletions

File tree

src/main/java/com/github/dockerjava/api/command/AttachContainerCmd.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ public interface AttachContainerCmd extends AsyncDockerCmd<AttachContainerCmd, F
4343
@CheckForNull
4444
public Boolean hasStderrEnabled();
4545

46+
@CheckForNull
47+
public InputStream getStdin();
48+
4649
public AttachContainerCmd withContainerId(@Nonnull String containerId);
4750

4851
/**
@@ -58,6 +61,8 @@ public interface AttachContainerCmd extends AsyncDockerCmd<AttachContainerCmd, F
5861

5962
public AttachContainerCmd withStdErr(Boolean stderr);
6063

64+
public AttachContainerCmd withStdIn(InputStream stdin);
65+
6166
public AttachContainerCmd withLogs(Boolean logs);
6267

6368
public static interface Exec extends DockerCmdAsyncExec<AttachContainerCmd, Frame> {

src/main/java/com/github/dockerjava/core/async/ResultCallbackTemplate.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ public void onError(Throwable throwable) {
6363

6464
@Override
6565
public void onComplete() {
66-
System.err.println("callback onComplete");
6766
try {
6867
close();
6968
} catch (IOException e) {

src/main/java/com/github/dockerjava/core/command/AttachContainerCmdImpl.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
import static com.google.common.base.Preconditions.checkNotNull;
44

5+
import java.io.InputStream;
6+
57
import com.github.dockerjava.api.command.AttachContainerCmd;
68
import com.github.dockerjava.api.model.Frame;
79

@@ -17,6 +19,8 @@
1719
* - true or false, includes stdout log. Defaults to false.
1820
* @param stderr
1921
* - true or false, includes stderr log. Defaults to false.
22+
* @param stdin
23+
* - null or {@link InputStream}, pass stream to stdin of the container.
2024
* @param timestamps
2125
* - true or false, if true, print timestamps for every log line. Defaults to false.
2226
*/
@@ -27,6 +31,8 @@ public class AttachContainerCmdImpl extends AbstrAsyncDockerCmd<AttachContainerC
2731

2832
private Boolean logs, followStream, timestamps, stdout, stderr;
2933

34+
private InputStream stdin;
35+
3036
public AttachContainerCmdImpl(AttachContainerCmd.Exec exec, String containerId) {
3137
super(exec);
3238
withContainerId(containerId);
@@ -62,6 +68,11 @@ public Boolean hasStderrEnabled() {
6268
return stderr;
6369
}
6470

71+
@Override
72+
public InputStream getStdin() {
73+
return stdin;
74+
}
75+
6576
@Override
6677
public AttachContainerCmd withContainerId(String containerId) {
6778
checkNotNull(containerId, "containerId was not specified");
@@ -93,6 +104,13 @@ public AttachContainerCmd withStdErr(Boolean stderr) {
93104
return this;
94105
}
95106

107+
@Override
108+
public AttachContainerCmd withStdIn(InputStream stdin) {
109+
checkNotNull(stdin, "stdin was not specified");
110+
this.stdin = stdin;
111+
return this;
112+
}
113+
96114
@Override
97115
public AttachContainerCmd withLogs(Boolean logs) {
98116
this.logs = logs;

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,15 @@ public AttachContainerCmdExec(WebTarget baseResource, DockerClientConfig dockerC
2626
protected AbstractCallbackNotifier<Frame> callbackNotifier(AttachContainerCmd command,
2727
ResultCallback<Frame> resultCallback) {
2828

29+
if (command.getStdin() != null)
30+
throw new UnsupportedOperationException(
31+
"Passing stdin to the container is currently not supported. Try experimental netty engine!");
32+
2933
WebTarget webTarget = getBaseResource().path("/containers/{id}/attach").resolveTemplate("id",
3034
command.getContainerId());
3135

3236
webTarget = booleanQueryParam(webTarget, "logs", command.hasLogsEnabled());
3337
webTarget = booleanQueryParam(webTarget, "stdout", command.hasStdoutEnabled());
34-
// webTarget = booleanQueryParam(webTarget, "stdin", command.hasStdinEnabled());
3538
webTarget = booleanQueryParam(webTarget, "stderr", command.hasStderrEnabled());
3639
webTarget = booleanQueryParam(webTarget, "stream", command.hasFollowStreamEnabled());
3740

src/main/java/com/github/dockerjava/netty/InvocationBuilder.java

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ public InvocationBuilder header(String name, String value) {
8686
return this;
8787
}
8888

89-
public ResponseCallback<Void> delete() {
89+
public void delete() {
9090

9191
HttpRequestProvider requestProvider = httpDeleteRequestProvider();
9292

@@ -100,7 +100,7 @@ public ResponseCallback<Void> delete() {
100100

101101
sendRequest(requestProvider, channel);
102102

103-
return callback;
103+
callback.awaitResult();
104104
}
105105

106106
public void get(ResultCallback<Frame> resultCallback) {
@@ -134,7 +134,7 @@ public <T> void get(TypeReference<T> typeReference, ResultCallback<T> resultCall
134134

135135
Channel channel = getChannel();
136136

137-
resultCallbackOnStart(channel, resultCallback);
137+
initCallback(channel, resultCallback);
138138

139139
JsonResponseCallbackHandler<T> jsonResponseHandler = new JsonResponseCallbackHandler<T>(typeReference,
140140
resultCallback);
@@ -276,7 +276,7 @@ public <T> void post(final Object entity, TypeReference<T> typeReference, final
276276

277277
Channel channel = getChannel();
278278

279-
resultCallbackOnStart(channel, resultCallback);
279+
initCallback(channel, resultCallback);
280280

281281
JsonResponseCallbackHandler<T> jsonResponseHandler = new JsonResponseCallbackHandler<T>(typeReference,
282282
resultCallback);
@@ -292,12 +292,11 @@ public <T> void post(final Object entity, TypeReference<T> typeReference, final
292292
return;
293293
}
294294

295-
private <T> void resultCallbackOnStart(final Channel channel, final ResultCallback<T> resultCallback) {
295+
private <T> void initCallback(final Channel channel, final ResultCallback<T> resultCallback) {
296296
Closeable closeable = new Closeable() {
297297
@Override
298298
public void close() throws IOException {
299299
try {
300-
System.err.println("closing channel");
301300
channel.close().sync();
302301
} catch (InterruptedException e) {
303302
resultCallback.onError(e);
@@ -327,14 +326,14 @@ private FullHttpRequest prepareGetRequest(String uri) {
327326
}
328327

329328
private HttpRequest preparePostRequest(String uri, Object entity) {
330-
return prepareRequest(uri, entity, HttpMethod.POST);
329+
return prepareEntityRequest(uri, entity, HttpMethod.POST);
331330
}
332331

333332
private HttpRequest preparePutRequest(String uri, Object entity) {
334-
return prepareRequest(uri, entity, HttpMethod.PUT);
333+
return prepareEntityRequest(uri, entity, HttpMethod.PUT);
335334
}
336335

337-
private HttpRequest prepareRequest(String uri, Object entity, HttpMethod httpMethod) {
336+
private HttpRequest prepareEntityRequest(String uri, Object entity, HttpMethod httpMethod) {
338337

339338
HttpRequest request = null;
340339

@@ -404,7 +403,7 @@ public <T> void post(TypeReference<T> typeReference, ResultCallback<T> resultCal
404403

405404
Channel channel = getChannel();
406405

407-
resultCallbackOnStart(channel, resultCallback);
406+
initCallback(channel, resultCallback);
408407

409408
JsonResponseCallbackHandler<T> jsonResponseHandler = new JsonResponseCallbackHandler<T>(typeReference,
410409
resultCallback);
@@ -440,7 +439,7 @@ public InputStream get() {
440439

441440
ResponseCallback<InputStream> resultCallback = new ResponseCallback<InputStream>();
442441

443-
resultCallbackOnStart(channel, resultCallback);
442+
initCallback(channel, resultCallback);
444443

445444
HttpResponseHandler responseHandler = new HttpResponseHandler(requestProvider, resultCallback);
446445

@@ -482,6 +481,5 @@ public void put(InputStream body, MediaType mediaType) {
482481
channel.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);
483482

484483
resultCallback.awaitResult();
485-
486484
};
487485
}

src/main/java/com/github/dockerjava/netty/exec/AttachContainerCmdExec.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,13 @@ protected Void execute0(AttachContainerCmd command, ResultCallback<Frame> result
2626

2727
webTarget = booleanQueryParam(webTarget, "logs", command.hasLogsEnabled());
2828
webTarget = booleanQueryParam(webTarget, "stdout", command.hasStdoutEnabled());
29-
// webTarget = booleanQueryParam(webTarget, "stdin", command.hasStdinEnabled());
3029
webTarget = booleanQueryParam(webTarget, "stderr", command.hasStderrEnabled());
30+
webTarget = booleanQueryParam(webTarget, "stdin", command.getStdin() != null);
3131
webTarget = booleanQueryParam(webTarget, "stream", command.hasFollowStreamEnabled());
3232

3333
LOGGER.trace("POST: {}", webTarget);
3434

35-
webTarget.request().post(null, System.in, resultCallback);
35+
webTarget.request().post(null, command.getStdin(), resultCallback);
3636

3737
return null;
3838
}

src/main/java/com/github/dockerjava/netty/exec/RemoveContainerCmdExec.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ protected Void execute(RemoveContainerCmd command) {
2525
webTarget = booleanQueryParam(webTarget, "force", command.hasForceEnabled());
2626

2727
LOGGER.trace("DELETE: {}", webTarget);
28-
return webTarget.request().accept(MediaType.APPLICATION_JSON).delete().awaitResult();
28+
webTarget.request().accept(MediaType.APPLICATION_JSON).delete();
29+
30+
return null;
2931
}
3032

3133
}

src/main/java/com/github/dockerjava/netty/exec/RemoveImageCmdExec.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ protected Void execute(RemoveImageCmd command) {
2323
webTarget = booleanQueryParam(webTarget, "noprune", command.hasNoPruneEnabled());
2424

2525
LOGGER.trace("DELETE: {}", webTarget);
26-
webTarget.request().delete().awaitResult();
26+
webTarget.request().delete();
2727

2828
return null;
2929
}

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

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
import static org.hamcrest.Matchers.isEmptyString;
66
import static org.hamcrest.Matchers.not;
77

8+
import java.io.ByteArrayInputStream;
89
import java.io.File;
10+
import java.io.InputStream;
911
import java.lang.reflect.Method;
1012
import java.util.concurrent.TimeUnit;
1113

@@ -104,6 +106,33 @@ public void onNext(Frame frame) {
104106
assertThat(callback.toString(), containsString("stdout\r\nstderr"));
105107
}
106108

109+
@Test(expectedExceptions = UnsupportedOperationException.class)
110+
public void attachContainerStdinUnsupported() throws Exception {
111+
112+
String snippet = "hello world";
113+
114+
CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withCmd("echo", snippet)
115+
.withTty(false).exec();
116+
117+
LOG.info("Created container: {}", container.toString());
118+
assertThat(container.getId(), not(isEmptyString()));
119+
120+
dockerClient.startContainerCmd(container.getId()).exec();
121+
122+
AttachContainerTestCallback callback = new AttachContainerTestCallback() {
123+
@Override
124+
public void onNext(Frame frame) {
125+
assertEquals(frame.getStreamType(), StreamType.STDOUT);
126+
super.onNext(frame);
127+
};
128+
};
129+
130+
InputStream stdin = new ByteArrayInputStream("".getBytes());
131+
132+
dockerClient.attachContainerCmd(container.getId()).withStdErr(true).withStdOut(true).withFollowStream(true)
133+
.withLogs(true).withStdIn(stdin).exec(callback).awaitCompletion(30, TimeUnit.SECONDS).close();
134+
}
135+
107136
public static class AttachContainerTestCallback extends AttachContainerResultCallback {
108137
private StringBuffer log = new StringBuffer();
109138

src/test/java/com/github/dockerjava/netty/exec/AttachContainerCmdExecTest.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
import static org.hamcrest.Matchers.isEmptyString;
66
import static org.hamcrest.Matchers.not;
77

8+
import java.io.ByteArrayInputStream;
89
import java.io.File;
10+
import java.io.InputStream;
911
import java.lang.reflect.Method;
1012
import java.util.concurrent.TimeUnit;
1113

@@ -17,6 +19,7 @@
1719
import org.testng.annotations.Test;
1820

1921
import com.github.dockerjava.api.command.CreateContainerResponse;
22+
import com.github.dockerjava.api.command.InspectContainerResponse;
2023
import com.github.dockerjava.api.model.Frame;
2124
import com.github.dockerjava.api.model.StreamType;
2225
import com.github.dockerjava.core.command.AttachContainerResultCallback;
@@ -72,6 +75,40 @@ public void onNext(Frame frame) {
7275
assertThat(callback.toString(), containsString(snippet));
7376
}
7477

78+
@Test
79+
public void attachContainerWithStdin() throws Exception {
80+
81+
String snippet = "hello world";
82+
83+
CreateContainerResponse container = dockerClient.createContainerCmd("busybox").withCmd("/bin/sh", "-c", "read line && echo $line")
84+
.withTty(false).withStdinOpen(true).exec();
85+
86+
LOG.info("Created container: {}", container.toString());
87+
assertThat(container.getId(), not(isEmptyString()));
88+
89+
dockerClient.startContainerCmd(container.getId()).exec();
90+
91+
InspectContainerResponse inspectContainerResponse = dockerClient.inspectContainerCmd(container.getId()).exec();
92+
93+
assertTrue(inspectContainerResponse.getState().getRunning());
94+
95+
AttachContainerTestCallback callback = new AttachContainerTestCallback() {
96+
97+
@Override
98+
public void onNext(Frame frame) {
99+
assertEquals(frame.getStreamType(), StreamType.STDOUT);
100+
super.onNext(frame);
101+
};
102+
};
103+
104+
InputStream stdin = new ByteArrayInputStream((snippet + "\n").getBytes());
105+
106+
dockerClient.attachContainerCmd(container.getId()).withStdErr(true).withStdOut(true).withFollowStream(true)
107+
.withStdIn(stdin).exec(callback).awaitCompletion(2, TimeUnit.SECONDS).close();
108+
109+
assertThat(callback.toString(), containsString(snippet));
110+
}
111+
75112
@Test
76113
public void attachContainerWithTTY() throws Exception {
77114

0 commit comments

Comments
 (0)