Skip to content

Commit 2ce5c20

Browse files
author
Marcus Linke
committed
Merge branch 'carlossg-list-containers-filters'
2 parents db06b33 + d2b618b commit 2ce5c20

File tree

6 files changed

+217
-7
lines changed

6 files changed

+217
-7
lines changed

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import java.util.List;
44

55
import com.github.dockerjava.api.model.Container;
6+
import com.github.dockerjava.api.model.Filters;
67

78
/**
89
* List containers
@@ -31,6 +32,8 @@ public interface ListContainersCmd extends DockerCmd<List<Container>> {
3132

3233
public String getBeforeId();
3334

35+
public Filters getFilters();
36+
3437
public ListContainersCmd withShowAll(boolean showAll);
3538

3639
public ListContainersCmd withShowSize(boolean showSize);
@@ -41,6 +44,8 @@ public interface ListContainersCmd extends DockerCmd<List<Container>> {
4144

4245
public ListContainersCmd withBefore(String before);
4346

47+
public ListContainersCmd withFilters(Filters filters);
48+
4449
public static interface Exec extends DockerCmdExec<ListContainersCmd, List<Container>> {
4550
}
4651

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.github.dockerjava.api.model;
22

3+
import java.util.Map;
4+
35
import org.apache.commons.lang.builder.ToStringBuilder;
46

57
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
@@ -31,6 +33,9 @@ public class Container {
3133
@JsonProperty("Ports")
3234
public Port[] ports;
3335

36+
@JsonProperty("Labels")
37+
public Map<String, String> labels;
38+
3439
@JsonProperty("Status")
3540
private String status;
3641

@@ -58,6 +63,10 @@ public Port[] getPorts() {
5863
return ports;
5964
}
6065

66+
public Map<String, String> getLabels() {
67+
return labels;
68+
}
69+
6170
public String[] getNames() {
6271
return names;
6372
}
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
package com.github.dockerjava.api.model;
2+
3+
import java.util.ArrayList;
4+
import java.util.Arrays;
5+
import java.util.HashMap;
6+
import java.util.List;
7+
import java.util.Map;
8+
import java.util.Map.Entry;
9+
10+
import javax.ws.rs.core.MediaType;
11+
12+
import com.fasterxml.jackson.core.JsonProcessingException;
13+
import com.fasterxml.jackson.databind.ObjectMapper;
14+
import com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider;
15+
16+
/**
17+
* Representation of Docker filters.
18+
*
19+
* @author Carlos Sanchez <carlos@apache.org>
20+
*
21+
*/
22+
public class Filters {
23+
24+
private static ObjectMapper OBJECT_MAPPER = new JacksonJaxbJsonProvider().locateMapper(Map.class,
25+
MediaType.APPLICATION_JSON_TYPE);
26+
27+
private Map<String, List<String>> filters = new HashMap<String, List<String>>();
28+
29+
public Filters() {
30+
}
31+
32+
public Filters withFilter(String key, String... value) {
33+
filters.put(key, Arrays.asList(value));
34+
return this;
35+
}
36+
37+
public List<String> getFilter(String key) {
38+
return filters.get(key);
39+
}
40+
41+
public Filters withImages(String... image) {
42+
withFilter("image", image);
43+
return this;
44+
}
45+
46+
public List<String> getImage() {
47+
return getFilter("image");
48+
}
49+
50+
public Filters withContainers(String... container) {
51+
withFilter("container", container);
52+
return this;
53+
}
54+
55+
public List<String> getContainer() {
56+
return getFilter("container");
57+
}
58+
59+
/**
60+
* Filter by labels
61+
*
62+
* @param labels
63+
* string array in the form ["key"] or ["key=value"] or a mix of both
64+
* @return
65+
*/
66+
public Filters withLabels(String... labels) {
67+
withFilter("label", labels);
68+
return this;
69+
}
70+
71+
/**
72+
* Filter by labels
73+
*
74+
* @param labels
75+
* {@link Map} of labels that contains label keys and values
76+
* @return
77+
*/
78+
public Filters withLabels(Map<String, String> labels) {
79+
withFilter("label", labelsMapToList(labels).toArray(new String[labels.size()]));
80+
return this;
81+
}
82+
83+
private static List<String> labelsMapToList(Map<String, String> labels) {
84+
List<String> result = new ArrayList<String>();
85+
for (Entry<String, String> entry : labels.entrySet()) {
86+
String rest = (entry.getValue() != null & !entry.getValue().isEmpty()) ? "=" + entry.getValue()
87+
: "";
88+
89+
String label = entry.getKey() + rest;
90+
91+
result.add(label);
92+
}
93+
return result;
94+
}
95+
96+
@Override
97+
public String toString() {
98+
try {
99+
return OBJECT_MAPPER.writeValueAsString(filters);
100+
} catch (JsonProcessingException e) {
101+
throw new RuntimeException(e);
102+
}
103+
}
104+
}

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

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

3-
import static com.google.common.base.Preconditions.checkArgument;
4-
import static com.google.common.base.Preconditions.checkNotNull;
3+
import static com.google.common.base.Preconditions.*;
54

65
import java.util.List;
76

87
import com.github.dockerjava.api.command.ListContainersCmd;
98
import com.github.dockerjava.api.model.Container;
9+
import com.github.dockerjava.api.model.Filters;
1010

1111
/**
1212
* List containers
@@ -32,6 +32,8 @@ public class ListContainersCmdImpl extends AbstrDockerCmd<ListContainersCmd, Lis
3232

3333
private String sinceId, beforeId;
3434

35+
private Filters filters;
36+
3537
public ListContainersCmdImpl(ListContainersCmd.Exec exec) {
3638
super(exec);
3739
}
@@ -61,6 +63,11 @@ public String getBeforeId() {
6163
return beforeId;
6264
}
6365

66+
@Override
67+
public Filters getFilters() {
68+
return filters;
69+
}
70+
6471
@Override
6572
public ListContainersCmd withShowAll(boolean showAll) {
6673
this.showAll = showAll;
@@ -94,11 +101,18 @@ public ListContainersCmd withBefore(String before) {
94101
return this;
95102
}
96103

104+
@Override
105+
public ListContainersCmd withFilters(Filters filters) {
106+
checkNotNull(filters, "filters was not specified");
107+
this.filters = filters;
108+
return this;
109+
}
110+
97111
@Override
98112
public String toString() {
99113
return new StringBuilder("ps ").append(showAll ? "--all=true" : "").append(showSize ? "--size=true" : "")
100-
.append(sinceId != null ? "--since " + sinceId : "")
101-
.append(beforeId != null ? "--before " + beforeId : "").append(limit != -1 ? "-n " + limit : "")
102-
.toString();
114+
.append(sinceId != null ? " --since " + sinceId : "")
115+
.append(beforeId != null ? " --before " + beforeId : "").append(limit != -1 ? "-n " + limit : "")
116+
.append(filters != null ? " --filters " + filters : "").toString();
103117
}
104118
}

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

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

3+
import static com.google.common.net.UrlEscapers.*;
4+
35
import java.util.List;
46

57
import javax.ws.rs.client.WebTarget;
@@ -32,6 +34,11 @@ protected List<Container> execute(ListContainersCmd command) {
3234
webResource = webResource.queryParam("limit", String.valueOf(command.getLimit()));
3335
}
3436

37+
if (command.getFilters() != null) {
38+
webResource = webResource.queryParam("filters",
39+
urlPathSegmentEscaper().escape(command.getFilters().toString()));
40+
}
41+
3542
LOGGER.trace("GET: {}", webResource);
3643
List<Container> containers = webResource.request().accept(MediaType.APPLICATION_JSON)
3744
.get(new GenericType<List<Container>>() {

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

Lines changed: 73 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
import java.lang.reflect.Method;
1515
import java.util.List;
16+
import java.util.Map;
1617

1718
import org.hamcrest.Matcher;
1819
import org.testng.ITestResult;
@@ -26,7 +27,9 @@
2627
import com.github.dockerjava.api.command.CreateContainerResponse;
2728
import com.github.dockerjava.api.command.InspectContainerResponse;
2829
import com.github.dockerjava.api.model.Container;
30+
import com.github.dockerjava.api.model.Filters;
2931
import com.github.dockerjava.client.AbstractDockerClientTest;
32+
import com.google.common.collect.ImmutableMap;
3033

3134
@Test(groups = "integration")
3235
public class ListContainersCmdImplTest extends AbstractDockerClientTest {
@@ -51,7 +54,6 @@ public void afterMethod(ITestResult result) {
5154
super.afterMethod(result);
5255
}
5356

54-
@Test
5557
public void testListContainers() throws DockerException {
5658

5759
String testImage = "busybox";
@@ -96,7 +98,76 @@ public void testListContainers() throws DockerException {
9698

9799
Container container2 = filteredContainers.get(0);
98100
assertThat(container2.getCommand(), not(isEmptyString()));
99-
assertThat(container2.getImage(), startsWith(testImage + ":"));
101+
assertThat(container2.getImage(), startsWith(testImage));
102+
}
103+
104+
@Test
105+
public void testListContainersWithLabelsFilter() throws DockerException {
106+
107+
String testImage = "busybox";
108+
109+
// need to block until image is pulled completely
110+
asString(dockerClient.pullImageCmd(testImage).exec());
111+
112+
List<Container> containers = dockerClient.listContainersCmd().withShowAll(true).exec();
113+
assertThat(containers, notNullValue());
114+
LOG.info("Container List: {}", containers);
115+
116+
int size = containers.size();
117+
118+
CreateContainerResponse container1 = dockerClient.createContainerCmd(testImage).withCmd("echo").exec();
119+
120+
assertThat(container1.getId(), not(isEmptyString()));
121+
122+
InspectContainerResponse inspectContainerResponse = dockerClient.inspectContainerCmd(container1.getId()).exec();
123+
124+
assertThat(inspectContainerResponse.getConfig().getImage(), is(equalTo(testImage)));
125+
126+
dockerClient.startContainerCmd(container1.getId()).exec();
127+
128+
LOG.info("container id: " + container1.getId());
129+
130+
List<Container> containers2 = dockerClient.listContainersCmd().withShowAll(true).exec();
131+
132+
for (Container container : containers2) {
133+
LOG.info("listContainer: id=" + container.getId() + " image=" + container.getImage());
134+
}
135+
136+
assertThat(size + 1, is(equalTo(containers2.size())));
137+
Matcher matcher = hasItem(hasField("id", startsWith(container1.getId())));
138+
assertThat(containers2, matcher);
139+
140+
List<Container> filteredContainers = filter(hasField("id", startsWith(container1.getId())), containers2);
141+
assertThat(filteredContainers.size(), is(equalTo(1)));
142+
143+
for (Container container : filteredContainers) {
144+
LOG.info("filteredContainer: " + container);
145+
}
146+
147+
Container container2 = filteredContainers.get(0);
148+
assertThat(container2.getCommand(), not(isEmptyString()));
149+
assertThat(container2.getImage(), startsWith(testImage));
150+
151+
152+
Map<String, String> labels = ImmutableMap.of("test", "docker-java");
153+
154+
// list with filter by label
155+
dockerClient.createContainerCmd(testImage).withCmd("echo").withLabels(labels)
156+
.exec();
157+
filteredContainers = dockerClient.listContainersCmd().withShowAll(true)
158+
.withFilters(new Filters().withLabels(labels)).exec();
159+
assertThat(filteredContainers.size(), is(equalTo(1)));
160+
Container container3 = filteredContainers.get(0);
161+
assertThat(container3.getCommand(), not(isEmptyString()));
162+
assertThat(container3.getImage(), startsWith(testImage));
163+
164+
filteredContainers = dockerClient.listContainersCmd().withShowAll(true)
165+
.withFilters(new Filters().withLabels("test")).exec();
166+
assertThat(filteredContainers.size(), is(equalTo(1)));
167+
container3 = filteredContainers.get(0);
168+
assertThat(container3.getCommand(), not(isEmptyString()));
169+
assertThat(container3.getImage(), startsWith(testImage));
170+
assertEquals(container3.getLabels(), labels);
100171
}
101172

102173
}

0 commit comments

Comments
 (0)