Skip to content

Commit 13d5305

Browse files
kowyKostyaSha
authored andcommitted
Add prune operations (docker-java#1164)
* add Prune operations * repair method name in DockerClient * make source code Checkstyle compliant * make source code Checkstyle compliant * add URL escape to filters parameter
1 parent 4b682c7 commit 13d5305

13 files changed

+385
-0
lines changed

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

+9
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
import com.github.dockerjava.api.command.LogSwarmObjectCmd;
4343
import com.github.dockerjava.api.command.PauseContainerCmd;
4444
import com.github.dockerjava.api.command.PingCmd;
45+
import com.github.dockerjava.api.command.PruneCmd;
4546
import com.github.dockerjava.api.command.PullImageCmd;
4647
import com.github.dockerjava.api.command.PushImageCmd;
4748
import com.github.dockerjava.api.command.RemoveContainerCmd;
@@ -68,6 +69,7 @@
6869
import com.github.dockerjava.api.exception.DockerException;
6970
import com.github.dockerjava.api.model.AuthConfig;
7071
import com.github.dockerjava.api.model.Identifier;
72+
import com.github.dockerjava.api.model.PruneType;
7173
import com.github.dockerjava.api.model.ServiceSpec;
7274
import com.github.dockerjava.api.model.SwarmSpec;
7375
import com.github.dockerjava.core.RemoteApiVersion;
@@ -391,6 +393,13 @@ public interface DockerClient extends Closeable {
391393
*/
392394
LogSwarmObjectCmd logTaskCmd(String taskId);
393395

396+
/**
397+
* Command to delete unused containers/images/networks/volumes
398+
*
399+
* @since {@link RemoteApiVersion#VERSION_1_25}
400+
*/
401+
PruneCmd pruneCmd(PruneType pruneType);
402+
394403
@Override
395404
void close() throws IOException;
396405

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

+7
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,13 @@ public interface DockerCmdExecFactory extends Closeable {
207207
*/
208208
ListTasksCmd.Exec listTasksCmdExec();
209209

210+
/**
211+
* Delete unused content (containers, images, volumes, networks, build relicts)
212+
*
213+
* @since {@link RemoteApiVersion#VERSION_1_25}
214+
*/
215+
PruneCmd.Exec pruneCmdExec();
216+
210217
@Override
211218
void close() throws IOException;
212219

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package com.github.dockerjava.api.command;
2+
3+
import com.github.dockerjava.api.model.PruneResponse;
4+
import com.github.dockerjava.api.model.PruneType;
5+
import com.github.dockerjava.core.RemoteApiVersion;
6+
7+
import javax.annotation.CheckForNull;
8+
import javax.annotation.Nonnull;
9+
import java.util.List;
10+
import java.util.Map;
11+
12+
/**
13+
* Delete unused content (containers, images, volumes, networks, build relicts)
14+
*
15+
* @since {@link RemoteApiVersion#VERSION_1_25}
16+
*/
17+
public interface PruneCmd extends SyncDockerCmd<PruneResponse> {
18+
19+
@Nonnull
20+
PruneType getPruneType();
21+
22+
@Nonnull
23+
String getApiPath();
24+
25+
@CheckForNull
26+
Map<String, List<String>> getFilters();
27+
28+
PruneCmd withPruneType(final PruneType pruneType);
29+
/**
30+
* Prune containers created before this timestamp
31+
* Meaningful only for CONTAINERS and IMAGES prune type
32+
* @param until Can be Unix timestamps, date formatted timestamps,
33+
* or Go duration strings (e.g. 10m, 1h30m) computed relative to the daemon machine’s time.
34+
*/
35+
PruneCmd withUntilFilter(String until);
36+
37+
/**
38+
* When set to true, prune only unused and untagged images. When set to false, all unused images are pruned.
39+
* Meaningful only for IMAGES prune type
40+
*/
41+
PruneCmd withDangling(Boolean dangling);
42+
43+
/**
44+
* Prune containers with the specified labels
45+
*/
46+
PruneCmd withLabelFilter(String... label);
47+
48+
@Override
49+
PruneResponse exec();
50+
51+
interface Exec extends DockerCmdSyncExec<PruneCmd, PruneResponse> {
52+
}
53+
54+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package com.github.dockerjava.api.model;
2+
3+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
4+
import com.fasterxml.jackson.annotation.JsonProperty;
5+
import org.apache.commons.lang.builder.EqualsBuilder;
6+
import org.apache.commons.lang.builder.HashCodeBuilder;
7+
8+
import java.io.Serializable;
9+
10+
/**
11+
* Delete unused content (containers, images, volumes, networks, build relicts)
12+
*/
13+
@JsonIgnoreProperties(ignoreUnknown = true)
14+
public class PruneResponse implements Serializable {
15+
private static final long serialVersionUID = 1L;
16+
17+
@JsonProperty("SpaceReclaimed")
18+
private Long spaceReclaimed;
19+
20+
/**
21+
* Default constructor for the deserialization.
22+
*/
23+
public PruneResponse() {
24+
}
25+
26+
/**
27+
* Constructor.
28+
*
29+
* @param spaceReclaimed Space reclaimed after purification
30+
*/
31+
public PruneResponse(Long spaceReclaimed) {
32+
this.spaceReclaimed = spaceReclaimed;
33+
}
34+
35+
/**
36+
* Disk space reclaimed in bytes
37+
*/
38+
public Long getSpaceReclaimed() {
39+
return spaceReclaimed;
40+
}
41+
42+
@Override
43+
public String toString() {
44+
StringBuilder sb = new StringBuilder();
45+
sb.append("PruneResponse {");
46+
sb.append(" spaceReclaimed: ").append(getSpaceReclaimed());
47+
sb.append("}");
48+
return sb.toString();
49+
}
50+
51+
@Override
52+
public boolean equals(Object o) {
53+
if (o instanceof Ulimit) {
54+
Ulimit other = (Ulimit) o;
55+
return new EqualsBuilder().append(spaceReclaimed, other.getName()).isEquals();
56+
} else {
57+
return super.equals(o);
58+
}
59+
}
60+
61+
@Override
62+
public int hashCode() {
63+
return new HashCodeBuilder().append(spaceReclaimed).toHashCode();
64+
}
65+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.github.dockerjava.api.model;
2+
3+
public enum PruneType {
4+
BUILD,
5+
CONTAINERS,
6+
IMAGES,
7+
NETWORKS,
8+
VOLUMES
9+
}

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

+7
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import com.github.dockerjava.api.command.LogSwarmObjectCmd;
4545
import com.github.dockerjava.api.command.PauseContainerCmd;
4646
import com.github.dockerjava.api.command.PingCmd;
47+
import com.github.dockerjava.api.command.PruneCmd;
4748
import com.github.dockerjava.api.command.PullImageCmd;
4849
import com.github.dockerjava.api.command.PushImageCmd;
4950
import com.github.dockerjava.api.command.RemoveContainerCmd;
@@ -110,6 +111,7 @@
110111
import com.github.dockerjava.core.exec.LogContainerCmdExec;
111112
import com.github.dockerjava.core.exec.PauseContainerCmdExec;
112113
import com.github.dockerjava.core.exec.PingCmdExec;
114+
import com.github.dockerjava.core.exec.PruneCmdExec;
113115
import com.github.dockerjava.core.exec.PullImageCmdExec;
114116
import com.github.dockerjava.core.exec.PushImageCmdExec;
115117
import com.github.dockerjava.core.exec.RemoveContainerCmdExec;
@@ -492,5 +494,10 @@ public LogSwarmObjectCmd.Exec logSwarmObjectExec(String endpoint) {
492494
return new LogSwarmObjectExec(getBaseResource(), getDockerClientConfig(), endpoint);
493495
}
494496

497+
@Override
498+
public PruneCmd.Exec pruneCmdExec() {
499+
return new PruneCmdExec(getBaseResource(), getDockerClientConfig());
500+
}
501+
495502
protected abstract WebTarget getBaseResource();
496503
}

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

+8
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import com.github.dockerjava.api.command.LogSwarmObjectCmd;
4545
import com.github.dockerjava.api.command.PauseContainerCmd;
4646
import com.github.dockerjava.api.command.PingCmd;
47+
import com.github.dockerjava.api.command.PruneCmd;
4748
import com.github.dockerjava.api.command.PullImageCmd;
4849
import com.github.dockerjava.api.command.PushImageCmd;
4950
import com.github.dockerjava.api.command.RemoveContainerCmd;
@@ -69,6 +70,7 @@
6970
import com.github.dockerjava.api.command.WaitContainerCmd;
7071
import com.github.dockerjava.api.model.AuthConfig;
7172
import com.github.dockerjava.api.model.Identifier;
73+
import com.github.dockerjava.api.model.PruneType;
7274
import com.github.dockerjava.api.model.ServiceSpec;
7375
import com.github.dockerjava.api.model.SwarmSpec;
7476
import com.github.dockerjava.core.command.AttachContainerCmdImpl;
@@ -113,6 +115,7 @@
113115
import com.github.dockerjava.core.command.LogSwarmObjectImpl;
114116
import com.github.dockerjava.core.command.PauseContainerCmdImpl;
115117
import com.github.dockerjava.core.command.PingCmdImpl;
118+
import com.github.dockerjava.core.command.PruneCmdImpl;
116119
import com.github.dockerjava.core.command.PullImageCmdImpl;
117120
import com.github.dockerjava.core.command.PushImageCmdImpl;
118121
import com.github.dockerjava.core.command.RemoveContainerCmdImpl;
@@ -579,6 +582,11 @@ public LogSwarmObjectCmd logTaskCmd(String taskId) {
579582
return new LogSwarmObjectImpl(getDockerCmdExecFactory().logSwarmObjectExec("tasks"), taskId);
580583
}
581584

585+
@Override
586+
public PruneCmd pruneCmd(PruneType pruneType) {
587+
return new PruneCmdImpl(getDockerCmdExecFactory().pruneCmdExec(), pruneType);
588+
}
589+
582590
@Override
583591
public ListTasksCmd listTasksCmd() {
584592
return new ListTasksCmdImpl(getDockerCmdExecFactory().listTasksCmdExec());
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
package com.github.dockerjava.core.command;
2+
3+
import com.github.dockerjava.api.command.PruneCmd;
4+
import com.github.dockerjava.api.model.PruneResponse;
5+
import com.github.dockerjava.api.model.PruneType;
6+
import com.github.dockerjava.core.util.FiltersBuilder;
7+
8+
import javax.annotation.CheckForNull;
9+
import javax.annotation.Nonnull;
10+
import java.util.List;
11+
import java.util.Map;
12+
13+
import static com.google.common.base.Preconditions.checkNotNull;
14+
15+
/**
16+
* Delete unused content (containers, images, volumes, networks, build relicts)
17+
*/
18+
public class PruneCmdImpl extends AbstrDockerCmd<PruneCmd, PruneResponse> implements PruneCmd {
19+
20+
private static final String BUILD_API_PATH = "/build/prune";
21+
private static final String CONTAINERS_API_PATH = "/containers/prune";
22+
private static final String IMAGES_API_PATH = "/images/prune";
23+
private static final String VOLUMES_API_PATH = "/volumes/prune";
24+
private static final String NETWORKS_API_PATH = "/networks/prune";
25+
26+
private FiltersBuilder filters = new FiltersBuilder();
27+
private PruneType pruneType;
28+
29+
public PruneCmdImpl(Exec exec, PruneType pruneType) {
30+
super(exec);
31+
this.pruneType = pruneType;
32+
}
33+
34+
@Nonnull
35+
@Override
36+
public PruneType getPruneType() {
37+
return pruneType;
38+
}
39+
40+
@Nonnull
41+
@Override
42+
public String getApiPath() {
43+
String apiPath;
44+
switch (getPruneType()) {
45+
case BUILD:
46+
apiPath = BUILD_API_PATH;
47+
break;
48+
case IMAGES:
49+
apiPath = IMAGES_API_PATH;
50+
break;
51+
case NETWORKS:
52+
apiPath = NETWORKS_API_PATH;
53+
break;
54+
case VOLUMES:
55+
apiPath = VOLUMES_API_PATH;
56+
break;
57+
default:
58+
apiPath = CONTAINERS_API_PATH;
59+
break;
60+
}
61+
return apiPath;
62+
}
63+
64+
@CheckForNull
65+
@Override
66+
public Map<String, List<String>> getFilters() {
67+
return filters.build();
68+
}
69+
70+
@Override
71+
public PruneCmd withPruneType(final PruneType pruneType) {
72+
checkNotNull(pruneType, "pruneType has not been specified");
73+
this.pruneType = pruneType;
74+
return this;
75+
}
76+
77+
@Override
78+
public PruneCmd withDangling(Boolean dangling) {
79+
checkNotNull(dangling, "dangling has not been specified");
80+
filters.withFilter("dangling", dangling ? "1" : "0");
81+
return this;
82+
}
83+
84+
@Override
85+
public PruneCmd withUntilFilter(final String until) {
86+
checkNotNull(until, "until has not been specified");
87+
filters.withUntil(until);
88+
return this;
89+
}
90+
91+
@Override
92+
public PruneCmd withLabelFilter(final String... labels) {
93+
checkNotNull(labels, "labels have not been specified");
94+
filters.withLabels(labels);
95+
return this;
96+
}
97+
98+
@Override
99+
public PruneResponse exec() {
100+
return super.exec();
101+
}
102+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package com.github.dockerjava.core.exec;
2+
3+
import com.fasterxml.jackson.core.type.TypeReference;
4+
import com.github.dockerjava.api.command.PruneCmd;
5+
import com.github.dockerjava.api.model.PruneResponse;
6+
import com.github.dockerjava.core.DockerClientConfig;
7+
import com.github.dockerjava.core.MediaType;
8+
import com.github.dockerjava.core.WebTarget;
9+
import com.github.dockerjava.core.util.FiltersEncoder;
10+
import org.slf4j.Logger;
11+
import org.slf4j.LoggerFactory;
12+
13+
public class PruneCmdExec extends AbstrSyncDockerCmdExec<PruneCmd, PruneResponse> implements PruneCmd.Exec {
14+
15+
private static final Logger LOGGER = LoggerFactory.getLogger(PruneCmdExec.class);
16+
17+
18+
public PruneCmdExec(WebTarget baseResource, DockerClientConfig dockerClientConfig) {
19+
super(baseResource, dockerClientConfig);
20+
}
21+
22+
@Override
23+
protected PruneResponse execute(PruneCmd command) {
24+
WebTarget webTarget = getBaseResource().path(command.getApiPath());
25+
26+
if (command.getFilters() != null && !command.getFilters().isEmpty()) {
27+
webTarget = webTarget.queryParam("filters", FiltersEncoder.jsonEncode(command.getFilters()));
28+
}
29+
30+
LOGGER.trace("POST: {}", webTarget);
31+
32+
PruneResponse response = webTarget.request().accept(MediaType.APPLICATION_JSON)
33+
.post(null, new TypeReference<PruneResponse>() { });
34+
35+
LOGGER.trace("Response: {}", response);
36+
37+
return response;
38+
}
39+
40+
}

0 commit comments

Comments
 (0)