Skip to content

Commit 9d268c0

Browse files
author
Marcus Linke
committed
Merge branch 'NirmataOSS-master'
2 parents bff4291 + dac0be3 commit 9d268c0

File tree

13 files changed

+409
-6
lines changed

13 files changed

+409
-6
lines changed

src/main/java/com/github/dockerjava/api/DockerClient.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@ public CopyFileFromContainerCmd copyFileFromContainerCmd(
114114

115115
public EventsCmd eventsCmd(EventCallback eventCallback);
116116

117+
public StatsCmd statsCmd(StatsCallback statsCallback);
118+
117119
@Override
118120
public void close() throws IOException;
119121

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ public interface DockerCmdExecFactory extends Closeable {
7878
public UnpauseContainerCmd.Exec createUnpauseContainerCmdExec();
7979

8080
public EventsCmd.Exec createEventsCmdExec();
81+
82+
public StatsCmd.Exec createStatsCmdExec();
83+
8184

8285
@Override
8386
public void close() throws IOException;
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.github.dockerjava.api.command;
2+
3+
import com.github.dockerjava.api.model.Statistics;
4+
5+
/**
6+
* Stats callback
7+
*/
8+
public interface StatsCallback {
9+
public void onStats(Statistics stats);
10+
public void onException(Throwable throwable);
11+
public void onCompletion(int numStats);
12+
public boolean isReceiving();
13+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package com.github.dockerjava.api.command;
2+
3+
import java.util.concurrent.ExecutorService;
4+
5+
6+
/**
7+
* Get stats
8+
*
9+
*/
10+
public interface StatsCmd extends DockerCmd<ExecutorService> {
11+
public StatsCmd withContainerId(String containerId);
12+
13+
public String getContainerId();
14+
15+
public StatsCmd withStatsCallback(StatsCallback statsCallback);
16+
17+
public StatsCallback getStatsCallback();
18+
19+
public static interface Exec extends DockerCmdExec<StatsCmd, ExecutorService> {
20+
}
21+
22+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package com.github.dockerjava.api.model;
2+
3+
import java.util.Map;
4+
5+
import org.apache.commons.lang.builder.ToStringBuilder;
6+
7+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
8+
import com.fasterxml.jackson.annotation.JsonProperty;
9+
10+
/**
11+
* Representation of a Docker statistics.
12+
*/
13+
@JsonIgnoreProperties(ignoreUnknown = true)
14+
public class Statistics {
15+
16+
@JsonProperty("read")
17+
private String read;
18+
19+
@JsonProperty("network")
20+
private Map<String,Object> networkStats;
21+
22+
@JsonProperty("memory_stats")
23+
private Map<String,Object> memoryStats;
24+
25+
@JsonProperty("blkio_stats")
26+
private Map<String,Object> blkioStats;
27+
28+
@JsonProperty("cpu_stats")
29+
private Map<String,Object> cpuStats;
30+
31+
public Map<String,Object> getNetworkStats() {
32+
return networkStats;
33+
}
34+
35+
public Map<String,Object> getCpuStats() {
36+
return cpuStats;
37+
}
38+
39+
public Map<String,Object> getMemoryStats() {
40+
return memoryStats;
41+
}
42+
43+
public Map<String,Object> getBlkioStats() {
44+
return blkioStats;
45+
}
46+
47+
@Override
48+
public String toString() {
49+
return ToStringBuilder.reflectionToString(this);
50+
}
51+
}

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,12 @@ public EventsCmd eventsCmd(EventCallback eventCallback) {
346346
return new EventsCmdImpl(getDockerCmdExecFactory()
347347
.createEventsCmdExec(), eventCallback);
348348
}
349+
350+
@Override
351+
public StatsCmd statsCmd(StatsCallback statsCallback) {
352+
return new StatsCmdImpl(getDockerCmdExecFactory()
353+
.createStatsCmdExec(), statsCallback);
354+
}
349355

350356
@Override
351357
public void close() throws IOException {
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package com.github.dockerjava.core.command;
2+
3+
import static com.google.common.base.Preconditions.checkNotNull;
4+
5+
import java.util.concurrent.ExecutorService;
6+
7+
import com.github.dockerjava.api.command.EventCallback;
8+
import com.github.dockerjava.api.command.EventsCmd;
9+
import com.github.dockerjava.api.command.StatsCallback;
10+
import com.github.dockerjava.api.command.StatsCmd;
11+
import com.github.dockerjava.api.command.TopContainerCmd;
12+
13+
/**
14+
* Stream docker stats
15+
*/
16+
public class StatsCmdImpl extends AbstrDockerCmd<StatsCmd, ExecutorService> implements StatsCmd {
17+
18+
private String containerId;
19+
private StatsCallback statsCallback;
20+
21+
public StatsCmdImpl(StatsCmd.Exec exec, StatsCallback statsCallback) {
22+
super(exec);
23+
withStatsCallback(statsCallback);
24+
}
25+
26+
@Override
27+
public StatsCmd withContainerId(String containerId) {
28+
checkNotNull(containerId, "containerId was not specified");
29+
this.containerId = containerId;
30+
return this;
31+
}
32+
33+
@Override
34+
public String getContainerId() {
35+
return containerId;
36+
}
37+
38+
@Override
39+
public StatsCmd withStatsCallback(StatsCallback statsCallback) {
40+
this.statsCallback = statsCallback;
41+
return this;
42+
}
43+
44+
45+
@Override
46+
public StatsCallback getStatsCallback() {
47+
return statsCallback;
48+
}
49+
50+
@Override
51+
public ExecutorService exec() {
52+
return super.exec();
53+
}
54+
55+
@Override
56+
public String toString() {
57+
return new StringBuilder("stats")
58+
.append(containerId != null ? " --id=" + containerId : "")
59+
.toString();
60+
}
61+
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,11 @@ public UnpauseContainerCmd.Exec createUnpauseContainerCmdExec() {
315315
public EventsCmd.Exec createEventsCmdExec() {
316316
return new EventsCmdExec(getBaseResource());
317317
}
318+
319+
@Override
320+
public StatsCmd.Exec createStatsCmdExec() {
321+
return new StatsCmdExec(getBaseResource());
322+
}
318323

319324
@Override
320325
public void close() throws IOException {

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

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ public Void call() throws Exception {
7979
// event from the docker server or the connection is terminated.
8080
// therefore we want to check before getting an event (to prevent a blocking operation
8181
// and after the event to make sure that the eventCallback is still interested in getting notified.
82-
while (eventCallback.isReceiving() &&
82+
while (eventCallback.isReceiving() &&
8383
jp.nextToken() != JsonToken.END_OBJECT && !jp.isClosed() &&
8484
eventCallback.isReceiving()) {
8585
try {
@@ -93,15 +93,14 @@ public Void call() throws Exception {
9393
} catch (Exception e) {
9494
eventCallback.onException(e);
9595
} finally {
96-
// call onCompletion before close because of https://github.com/docker-java/docker-java/issues/196
96+
if (response != null) {
97+
response.close();
98+
}
9799
try {
98100
eventCallback.onCompletion(numEvents);
99101
} catch (Exception e) {
100102
eventCallback.onException(e);
101103
}
102-
if (response != null) {
103-
response.close();
104-
}
105104
}
106105

107106
return null;
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
package com.github.dockerjava.jaxrs;
2+
3+
import static com.google.common.base.Preconditions.checkNotNull;
4+
5+
import java.io.InputStream;
6+
import java.util.concurrent.Callable;
7+
import java.util.concurrent.ExecutorService;
8+
import java.util.concurrent.Executors;
9+
10+
import javax.ws.rs.client.WebTarget;
11+
import javax.ws.rs.core.Response;
12+
13+
import org.slf4j.Logger;
14+
import org.slf4j.LoggerFactory;
15+
16+
import com.fasterxml.jackson.core.JsonFactory;
17+
import com.fasterxml.jackson.core.JsonParser;
18+
import com.fasterxml.jackson.core.JsonToken;
19+
import com.fasterxml.jackson.databind.ObjectMapper;
20+
import com.github.dockerjava.api.command.StatsCallback;
21+
import com.github.dockerjava.api.command.StatsCmd;
22+
import com.github.dockerjava.api.model.Statistics;
23+
import com.github.dockerjava.jaxrs.util.WrappedResponseInputStream;
24+
25+
public class StatsCmdExec extends AbstrDockerCmdExec<StatsCmd, ExecutorService> implements StatsCmd.Exec {
26+
private static final Logger LOGGER = LoggerFactory.getLogger(StatsCmdExec.class);
27+
28+
public StatsCmdExec(WebTarget baseResource) {
29+
super(baseResource);
30+
}
31+
32+
@Override
33+
protected ExecutorService execute(StatsCmd command) {
34+
ExecutorService executorService = Executors.newSingleThreadExecutor();
35+
36+
WebTarget webResource = getBaseResource().path("/containers/{id}/stats")
37+
.resolveTemplate("id", command.getContainerId());
38+
39+
LOGGER.trace("GET: {}", webResource);
40+
StatsNotifier eventNotifier = StatsNotifier.create(command.getStatsCallback(), webResource);
41+
executorService.submit(eventNotifier);
42+
return executorService;
43+
}
44+
45+
private static class StatsNotifier implements Callable<Void> {
46+
private static final JsonFactory JSON_FACTORY = new JsonFactory();
47+
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
48+
49+
private final StatsCallback statsCallback;
50+
private final WebTarget webTarget;
51+
52+
private StatsNotifier(StatsCallback statsCallback, WebTarget webTarget) {
53+
this.statsCallback = statsCallback;
54+
this.webTarget = webTarget;
55+
}
56+
57+
public static StatsNotifier create(StatsCallback statsCallback, WebTarget webTarget) {
58+
checkNotNull(statsCallback, "An StatsCallback must be provided");
59+
checkNotNull(webTarget, "An WebTarget must be provided");
60+
return new StatsNotifier(statsCallback, webTarget);
61+
}
62+
63+
@Override
64+
public Void call() throws Exception {
65+
int numEvents = 0;
66+
Response response = null;
67+
try {
68+
response = webTarget.request().get(Response.class);
69+
InputStream inputStream = new WrappedResponseInputStream(
70+
response);
71+
JsonParser jp = JSON_FACTORY.createParser(inputStream);
72+
// The following condition looks strange but jp.nextToken() will block until there is an
73+
// event from the docker server or the connection is terminated.
74+
// therefore we want to check before getting an event (to prevent a blocking operation
75+
// and after the event to make sure that the eventCallback is still interested in getting notified.
76+
while (statsCallback.isReceiving() &&
77+
jp.nextToken() != JsonToken.END_OBJECT && !jp.isClosed() &&
78+
statsCallback.isReceiving()) {
79+
try {
80+
statsCallback.onStats(OBJECT_MAPPER.readValue(jp,
81+
Statistics.class));
82+
} catch (Exception e) {
83+
statsCallback.onException(e);
84+
}
85+
numEvents++;
86+
}
87+
} catch (Exception e) {
88+
statsCallback.onException(e);
89+
} finally {
90+
if (response != null) {
91+
response.close();
92+
}
93+
try {
94+
statsCallback.onCompletion(numEvents);
95+
} catch (Exception e) {
96+
statsCallback.onException(e);
97+
}
98+
}
99+
100+
return null;
101+
}
102+
}
103+
}

0 commit comments

Comments
 (0)