Skip to content
This repository has been archived by the owner on Mar 21, 2022. It is now read-only.

ISSUE-737: Add ManagerStatus into Node #790

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions src/main/java/com/spotify/docker/client/DefaultDockerClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -1974,6 +1974,32 @@ public List<Node> listNodes() throws DockerException, InterruptedException {
return request(GET, NODE_LIST, resource, resource.request(APPLICATION_JSON_TYPE));
}

@Override
public List<Node> listNodes(Node.Criteria criteria) throws DockerException, InterruptedException {
assertApiVersionIsAbove("1.24");
final Map<String, List<String>> filters = new HashMap<>();

if (criteria.nodeId() != null) {
filters.put("id", Collections.singletonList(criteria.nodeId()));
}
if (criteria.label() != null) {
filters.put("label", Collections.singletonList(criteria.label()));
}
if (criteria.membership() != null) {
filters.put("membership", Collections.singletonList(criteria.membership()));
}
if (criteria.nodeName() != null) {
filters.put("name", Collections.singletonList(criteria.nodeName()));
}
if (criteria.nodeRole() != null) {
filters.put("role", Collections.singletonList(criteria.nodeRole()));
}

WebTarget resource = resource().path("nodes");
resource = resource.queryParam("filters", urlEncodeFilters(filters));
return request(GET, NODE_LIST, resource, resource.request(APPLICATION_JSON_TYPE));
}

@Override
public NodeInfo inspectNode(final String nodeId) throws DockerException, InterruptedException {
assertApiVersionIsAbove("1.24");
Expand Down
12 changes: 12 additions & 0 deletions src/main/java/com/spotify/docker/client/DockerClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -2850,6 +2850,18 @@ public ListVolumesFilterParam(String name, String value) {
*/
List<Node> listNodes() throws DockerException, InterruptedException;

/**
* List swarm nodes that match the given criteria. Only available in Docker API &gt;= 1.24.
*
* @param criteria Node listing and filtering options.
* @return A list of nodes.
*
* @throws DockerException if a server error occurred (500)
* @throws InterruptedException If the thread is interrupted
* @since Docker 1.12, API version 1.24
*/
List<Node> listNodes(final Node.Criteria criteria) throws DockerException, InterruptedException;

/**
* Inspects a swarm node. Only available in Docker API &gt;= 1.24.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,14 @@
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.auto.value.AutoValue;
import javax.annotation.Nullable;


@AutoValue
@JsonAutoDetect(fieldVisibility = ANY, getterVisibility = NONE, setterVisibility = NONE)
public abstract class ManagerStatus {

@Nullable
@JsonProperty("Leader")
public abstract Boolean leader();

Expand Down
72 changes: 69 additions & 3 deletions src/main/java/com/spotify/docker/client/messages/swarm/Node.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.auto.value.AutoValue;

import java.util.Date;
import javax.annotation.Nullable;

@AutoValue
@JsonAutoDetect(fieldVisibility = ANY, getterVisibility = NONE, setterVisibility = NONE)
Expand All @@ -52,13 +52,79 @@ public abstract class Node {
@JsonProperty("Description")
public abstract NodeDescription description();

@JsonProperty("Status")
public abstract NodeStatus status();

@Nullable
@JsonProperty("ManagerStatus")
public abstract ManagerStatus managerStatus();

@JsonCreator
static Node create(@JsonProperty("ID") final String id,
@JsonProperty("Version") final Version version,
@JsonProperty("CreatedAt") final Date createdAt,
@JsonProperty("UpdatedAt") final Date updatedAt,
@JsonProperty("Spec") final NodeSpec nodeSpec,
@JsonProperty("Description") final NodeDescription description) {
return new AutoValue_Node(id, version, createdAt, updatedAt, nodeSpec, description);
@JsonProperty("Description") final NodeDescription description,
@JsonProperty("Status") final NodeStatus nodeStatus,
@JsonProperty("ManagerStatus") final ManagerStatus managerStatus) {
return new AutoValue_Node(id, version, createdAt, updatedAt, nodeSpec, description,
nodeStatus, managerStatus);
}

@AutoValue
public abstract static class Criteria {
/**
* Filter by node id.
*/
@Nullable
public abstract String nodeId();

/**
* Filter by label.
*/
@Nullable
public abstract String label();

/**
* Filter by membership {accepted | pending}.
*/
@Nullable
public abstract String membership();

/**
* Filter by node name.
*/
@Nullable
public abstract String nodeName();

/**
* Filter by node role {manager | worker}.
*/
@Nullable
public abstract String nodeRole();

public static Builder builder() {
return new AutoValue_Node_Criteria.Builder();
}

@AutoValue.Builder
public abstract static class Builder {
public abstract Builder nodeId(String nodeId);

public abstract Builder label(String label);

public abstract Builder nodeName(String nodeName);

public abstract Builder membership(String membership);

public abstract Builder nodeRole(String nodeRole);

public abstract Node.Criteria build();
}
}

public static Node.Criteria.Builder find() {
return AutoValue_Node_Criteria.builder();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.auto.value.AutoValue;


import java.util.Date;
import javax.annotation.Nullable;

Expand Down Expand Up @@ -58,6 +56,7 @@ public abstract class NodeInfo {
@JsonProperty("Status")
public abstract NodeStatus status();

@Nullable
@JsonProperty("ManagerStatus")
public abstract ManagerStatus managerStatus();

Expand All @@ -77,54 +76,4 @@ public static AutoValue_NodeInfo create(@JsonProperty("ID") final String id,
return new AutoValue_NodeInfo(id, version, createdAt, updatedAt,
nodeSpec, description, nodeStatus, managerStatus);
}

@AutoValue
public abstract static class Criteria {
/**
* Filter by node id.
*/
@Nullable
public abstract String nodeId();

/**
* Filter by label.
*/
@Nullable
public abstract String label();

/**
* Filter by node name.
*/
@Nullable
public abstract String nodeName();

/**
* Filter by node role {manager | worker}.
*/
@Nullable
public abstract String nodeRole();

public static Builder builder() {
return new AutoValue_NodeInfo_Criteria.Builder();
}


@AutoValue.Builder
public abstract static class Builder {
public abstract Builder nodeId(String nodeId);

public abstract Builder label(String label);

public abstract Builder nodeName(String nodeName);

public abstract Builder nodeRole(String nodeRole);

public abstract NodeInfo.Criteria build();
}
}


public static NodeInfo.Criteria.Builder find() {
return AutoValue_NodeInfo_Criteria.builder();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

package com.spotify.docker.client;

import static com.spotify.docker.FixtureUtil.fixture;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.equalTo;
Expand All @@ -42,7 +43,6 @@
import com.google.common.collect.Lists;
import com.google.common.io.BaseEncoding;
import com.google.common.io.Resources;
import com.spotify.docker.FixtureUtil;
import com.spotify.docker.client.auth.RegistryAuthSupplier;
import com.spotify.docker.client.exceptions.DockerCertificateException;
import com.spotify.docker.client.exceptions.DockerException;
Expand All @@ -54,7 +54,9 @@
import com.spotify.docker.client.messages.RegistryConfigs;
import com.spotify.docker.client.messages.ServiceCreateResponse;
import com.spotify.docker.client.messages.swarm.ContainerSpec;
import com.spotify.docker.client.messages.swarm.EngineConfig;
import com.spotify.docker.client.messages.swarm.Node;
import com.spotify.docker.client.messages.swarm.NodeDescription;
import com.spotify.docker.client.messages.swarm.NodeInfo;
import com.spotify.docker.client.messages.swarm.NodeSpec;
import com.spotify.docker.client.messages.swarm.ServiceSpec;
Expand Down Expand Up @@ -338,6 +340,7 @@ public void testInspectNode() throws Exception {
enqueueServerApiResponse(200, "fixtures/1.28/nodeInfo.json");

final NodeInfo nodeInfo = dockerClient.inspectNode("24ifsmvkjbyhk");

assertThat(nodeInfo, notNullValue());
assertThat(nodeInfo.id(), is("24ifsmvkjbyhk"));
assertThat(nodeInfo.status(), notNullValue());
Expand All @@ -348,6 +351,53 @@ public void testInspectNode() throws Exception {
assertThat(nodeInfo.managerStatus().reachability(), is("reachable"));
}

@Test
public void testInspectNonLeaderNode() throws Exception {
final DefaultDockerClient dockerClient = new DefaultDockerClient(builder);

enqueueServerApiVersion("1.27");

server.enqueue(new MockResponse()
.setResponseCode(200)
.addHeader("Content-Type", "application/json")
.setBody(
fixture("fixtures/1.27/nodeInfoNonLeader.json")
)
);

NodeInfo nodeInfo = dockerClient.inspectNode("24ifsmvkjbyhk");
assertThat(nodeInfo, notNullValue());
assertThat(nodeInfo.id(), is("24ifsmvkjbyhk"));
assertThat(nodeInfo.status(), notNullValue());
assertThat(nodeInfo.status().addr(), is("172.17.0.2"));
assertThat(nodeInfo.managerStatus(), notNullValue());
assertThat(nodeInfo.managerStatus().addr(), is("172.17.0.2:2377"));
assertThat(nodeInfo.managerStatus().leader(), nullValue());
assertThat(nodeInfo.managerStatus().reachability(), is("reachable"));
}

@Test
public void testInspectNodeNonManager() throws Exception {
final DefaultDockerClient dockerClient = new DefaultDockerClient(builder);

enqueueServerApiVersion("1.27");

server.enqueue(new MockResponse()
.setResponseCode(200)
.addHeader("Content-Type", "application/json")
.setBody(
fixture("fixtures/1.27/nodeInfoNonManager.json")
)
);

NodeInfo nodeInfo = dockerClient.inspectNode("24ifsmvkjbyhk");
assertThat(nodeInfo, notNullValue());
assertThat(nodeInfo.id(), is("24ifsmvkjbyhk"));
assertThat(nodeInfo.status(), notNullValue());
assertThat(nodeInfo.status().addr(), is("172.17.0.2"));
assertThat(nodeInfo.managerStatus(), nullValue());
}

@Test(expected = NodeNotFoundException.class)
public void testInspectMissingNode() throws Exception {
final DefaultDockerClient dockerClient = new DefaultDockerClient(builder);
Expand Down Expand Up @@ -541,13 +591,76 @@ private void enqueueServerApiEmptyResponse(final int statusCode) {
);
}

@Test
public void testListNodes() throws Exception {
final DefaultDockerClient dockerClient = new DefaultDockerClient(builder);

enqueueServerApiVersion("1.28");

server.enqueue(new MockResponse()
.setResponseCode(200)
.addHeader("Content-Type", "application/json")
.setBody(
fixture("fixtures/1.28/listNodes.json")
)
);

final List<Node> nodes = dockerClient.listNodes();
assertThat(nodes.size(), equalTo(1));

final Node node = nodes.get(0);

assertThat(node, notNullValue());
assertThat(node.id(), is("24ifsmvkjbyhk"));
assertThat(node.version().index(), is(8L));

final NodeSpec nodeSpec = node.spec();
assertThat(nodeSpec.name(), is("my-node"));
assertThat(nodeSpec.role(), is("manager"));
assertThat(nodeSpec.availability(), is("active"));
assertThat(nodeSpec.labels().keySet(), contains("foo"));

final NodeDescription desc = node.description();
assertThat(desc.hostname(), is("bf3067039e47"));
assertThat(desc.platform().architecture(), is("x86_64"));
assertThat(desc.platform().os(), is("linux"));
assertThat(desc.resources().memoryBytes(), is(8272408576L));
assertThat(desc.resources().nanoCpus(), is(4000000000L));

final EngineConfig engine = desc.engine();
assertThat(engine.engineVersion(), is("17.04.0"));
assertThat(engine.labels().keySet(), contains("foo"));
assertThat(engine.plugins().size(), equalTo(4));

assertThat(node.status(), notNullValue());
assertThat(node.status().addr(), is("172.17.0.2"));
assertThat(node.managerStatus(), notNullValue());
assertThat(node.managerStatus().addr(), is("172.17.0.2:2377"));
assertThat(node.managerStatus().leader(), is(true));
assertThat(node.managerStatus().reachability(), is("reachable"));
}

@Test(expected = DockerException.class)
public void testListNodesWithServerError() throws Exception {
final DefaultDockerClient dockerClient = new DefaultDockerClient(builder);

enqueueServerApiVersion("1.28");

server.enqueue(new MockResponse()
.setResponseCode(500)
.addHeader("Content-Type", "application/json")
);

dockerClient.listNodes();
}

private void enqueueServerApiResponse(final int statusCode, final String fileName)
throws IOException {
server.enqueue(new MockResponse()
.setResponseCode(statusCode)
.addHeader("Content-Type", "application/json")
.setBody(
FixtureUtil.fixture(fileName)
fixture(fileName)
)
);
}
Expand Down
Loading