Skip to content

Commit

Permalink
Merge pull request spotify#697 from Noodle05/master
Browse files Browse the repository at this point in the history
Implement "hosts", "healthcheck" and "secrets" in service createapi
  • Loading branch information
davidxia authored Mar 27, 2017
2 parents 80da50a + f070736 commit fde61d5
Show file tree
Hide file tree
Showing 4 changed files with 277 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.spotify.docker.client.messages.ContainerConfig;
import com.spotify.docker.client.messages.mount.Mount;

import java.util.List;
Expand Down Expand Up @@ -89,6 +90,27 @@ public abstract class ContainerSpec {
@JsonProperty("StopGracePeriod")
public abstract Long stopGracePeriod();

/**
* @since API 1.26
*/
@Nullable
@JsonProperty("Healthcheck")
public abstract ContainerConfig.Healthcheck healthcheck();

/**
* @since API 1.26
*/
@Nullable
@JsonProperty("Hosts")
public abstract ImmutableList<String> hosts();

/**
* @since API 1.26
*/
@Nullable
@JsonProperty("Secrets")
public abstract ImmutableList<SecretBind> secrets();

@AutoValue.Builder
public abstract static class Builder {

Expand Down Expand Up @@ -304,6 +326,12 @@ public Builder withStopGracePeriod(final long stopGracePeriod) {
return this;
}

public abstract Builder healthcheck(ContainerConfig.Healthcheck healthcheck);

public abstract Builder hosts(List<String> hosts);

public abstract Builder secrets(List<SecretBind> secrets);

public abstract ContainerSpec build();
}

Expand All @@ -324,7 +352,10 @@ static ContainerSpec create(
@JsonProperty("Groups") final List<String> groups,
@JsonProperty("TTY") final Boolean tty,
@JsonProperty("Mounts") final List<Mount> mounts,
@JsonProperty("StopGracePeriod") final Long stopGracePeriod) {
@JsonProperty("StopGracePeriod") final Long stopGracePeriod,
@JsonProperty("Healthcheck") final ContainerConfig.Healthcheck healthcheck,
@JsonProperty("Hosts") final List<String> hosts,
@JsonProperty("Secrets") final List<SecretBind> secrets) {
final Builder builder = builder()
.image(image)
.hostname(hostname)
Expand All @@ -335,7 +366,9 @@ static ContainerSpec create(
.groups(groups)
.tty(tty)
.mounts(mounts)
.stopGracePeriod(stopGracePeriod);
.stopGracePeriod(stopGracePeriod)
.healthcheck(healthcheck)
.hosts(hosts);

if (labels != null) {
builder.labels(labels);
Expand All @@ -345,6 +378,10 @@ static ContainerSpec create(
builder.command(command);
}

if (secrets != null) {
builder.secrets(secrets);
}

return builder.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*-
* -\-\-
* docker-client
* --
* Copyright (C) 2016 Spotify AB
* --
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* -/-/-
*/

package com.spotify.docker.client.messages.swarm;

import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.ANY;
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.NONE;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.auto.value.AutoValue;

@AutoValue
@JsonAutoDetect(fieldVisibility = ANY, getterVisibility = NONE, setterVisibility = NONE)
public abstract class SecretBind {
@JsonProperty("File")
public abstract SecretFile file();

@JsonProperty("SecretID")
public abstract String secretId();

@JsonProperty("SecretName")
public abstract String secretName();

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

@AutoValue.Builder
public abstract static class Builder {

public abstract Builder file(SecretFile file);

public abstract Builder secretId(String secretId);

public abstract Builder secretName(String secretName);

public abstract SecretBind build();
}

@JsonCreator
static SecretBind create(
@JsonProperty("File") SecretFile file,
@JsonProperty("SecretID") String secretId,
@JsonProperty("SecretName") String secretName) {
return builder()
.file(file)
.secretId(secretId)
.secretName(secretName)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*-
* -\-\-
* docker-client
* --
* Copyright (C) 2016 Spotify AB
* --
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* -/-/-
*/

package com.spotify.docker.client.messages.swarm;

import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.ANY;
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.NONE;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
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 SecretFile {
@JsonProperty("Name")
public abstract String name();

@Nullable
@JsonProperty("UID")
public abstract String uid();

@Nullable
@JsonProperty("GID")
public abstract String gid();

@Nullable
@JsonProperty("Mode")
public abstract Long mode();

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

@AutoValue.Builder
public abstract static class Builder {

public abstract Builder name(String name);

public abstract Builder uid(String uid);

public abstract Builder gid(String gid);

public abstract Builder mode(Long mode);

public abstract SecretFile build();
}

@JsonCreator
static SecretFile create(
@JsonProperty("Name") String name,
@JsonProperty("UID") String uid,
@JsonProperty("GID") String gid,
@JsonProperty("Mode") Long mode) {
return builder()
.name(name)
.uid(uid)
.gid(gid)
.mode(mode)
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,9 @@
import com.spotify.docker.client.messages.swarm.ResourceRequirements;
import com.spotify.docker.client.messages.swarm.RestartPolicy;
import com.spotify.docker.client.messages.swarm.Secret;
import com.spotify.docker.client.messages.swarm.SecretBind;
import com.spotify.docker.client.messages.swarm.SecretCreateResponse;
import com.spotify.docker.client.messages.swarm.SecretFile;
import com.spotify.docker.client.messages.swarm.SecretSpec;
import com.spotify.docker.client.messages.swarm.Service;
import com.spotify.docker.client.messages.swarm.ServiceMode;
Expand Down Expand Up @@ -4516,16 +4518,98 @@ public void testCreateServiceWithDefaults() throws Exception {
assertThat(restartPolicy.maxAttempts(), equalTo(0));
}

@Test
public void testCreateServiceWithSecretHostnameHostsAndHealthcheck() throws Exception {
requireDockerApiVersionAtLeast("1.26", "swarm support");

final String hostname = "tshost-{{.Task.Slot}}";
final String[] hosts = {"127.0.0.1 test.local", "127.0.0.1 test"};
final String[] healthcheckCmd = {"ping", "-c", "1", "127.0.0.1"};

for (final Secret secret : sut.listSecrets()) {
sut.deleteSecret(secret.id());
}
assertThat(sut.listSecrets().size(), equalTo(0));

final String secretData = Base64.encodeAsString("testdata".getBytes());

final Map<String, String> labels = ImmutableMap.of("foo", "bar", "1", "a");

final SecretSpec secretSpec = SecretSpec.builder()
.name("asecret")
.data(secretData)
.labels(labels)
.build();

final SecretCreateResponse secretResponse = sut.createSecret(secretSpec);
final String secretId = secretResponse.id();
assertThat(secretId, is(notNullValue()));

final SecretFile secretFile = SecretFile.builder()
.name("bsecret")
.uid("1001")
.gid("1002")
.mode(0640L)
.build();
final SecretBind secretBind = SecretBind.builder()
.file(secretFile)
.secretId(secretId)
.secretName("asecret")
.build();

final String[] commandLine = {"ping", "-c4", "localhost"};
final TaskSpec taskSpec = TaskSpec
.builder()
.containerSpec(ContainerSpec.builder().image("alpine")
.secrets(Arrays.asList(secretBind))
.hostname(hostname)
.hosts(Arrays.asList(hosts))
.healthcheck(Healthcheck.create(Arrays.asList(healthcheckCmd), 30L, 3L, 3))
.command(commandLine).build())
.build();
final String serviceName = randomName();
final ServiceSpec spec = ServiceSpec.builder()
.name(serviceName)
.taskTemplate(taskSpec)
.build();

final ServiceCreateResponse response = sut.createService(spec);

final Service service = sut.inspectService(response.id());

assertThat(service.spec().name(), is(serviceName));
final Matcher<String> imageMatcher = dockerApiVersionLessThan("1.25")
? is("alpine") : startsWith("alpine:latest@sha256:");
assertThat(service.spec().taskTemplate().containerSpec().image(), imageMatcher);
assertThat(service.spec().taskTemplate().containerSpec().hostname(), is(hostname));
assertThat(service.spec().taskTemplate().containerSpec().hosts(), containsInAnyOrder(hosts));
assertThat(service.spec().taskTemplate().containerSpec().secrets().size(),
equalTo(1));
SecretBind secret = service.spec().taskTemplate().containerSpec().secrets().get(0);
assertThat(secret.secretId(), equalTo(secretId));
assertThat(secret.secretName(), equalTo("asecret"));
assertThat(secret.file().name(), equalTo("bsecret"));
assertThat(secret.file().uid(), equalTo("1001"));
assertThat(secret.file().gid(), equalTo("1002"));
assertThat(secret.file().mode(), equalTo(0640L));
assertThat(service.spec().taskTemplate().containerSpec().healthcheck().test(),
equalTo(Arrays.asList(healthcheckCmd)));
assertThat(service.spec().taskTemplate().containerSpec().healthcheck().interval(),
equalTo(30L));
assertThat(service.spec().taskTemplate().containerSpec().healthcheck().timeout(),
equalTo(3L));
assertThat(service.spec().taskTemplate().containerSpec().healthcheck().retries(),
equalTo(3));
}

@Test
public void testInspectService() throws Exception {
requireDockerApiVersionAtLeast("1.24", "swarm support");

final String[] commandLine = {"ping", "-c4", "localhost"};
final String hostname = "tshost-{{.Task.Slot}}";
final TaskSpec taskSpec = TaskSpec
.builder()
.containerSpec(ContainerSpec.builder().image("alpine")
.hostname(hostname)
.command(commandLine).build())
.logDriver(Driver.builder().name("json-file").addOption("max-file", "3")
.addOption("max-size", "10M").build())
Expand Down Expand Up @@ -4563,9 +4647,6 @@ public void testInspectService() throws Exception {
final Matcher<String> imageMatcher = dockerApiVersionLessThan("1.25")
? is("alpine") : startsWith("alpine:latest@sha256:");
assertThat(service.spec().taskTemplate().containerSpec().image(), imageMatcher);
if (dockerApiVersionAtLeast("1.26")) {
assertThat(service.spec().taskTemplate().containerSpec().hostname(), is(hostname));
}
assertThat(service.spec().taskTemplate().containerSpec().command(),
equalTo(Arrays.asList(commandLine)));
}
Expand Down

0 comments on commit fde61d5

Please sign in to comment.