Skip to content
This repository has been archived by the owner on Sep 29, 2021. It is now read-only.

Commit

Permalink
Add Javadoc, and tweak some private method naming.
Browse files Browse the repository at this point in the history
  • Loading branch information
Nic Cope committed Dec 10, 2015
1 parent 640a857 commit 8dfca4a
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 8 deletions.
Expand Up @@ -19,8 +19,19 @@


import com.spotify.helios.client.HeliosClient; import com.spotify.helios.client.HeliosClient;


/**
* A HeliosDeployment represents a collection of Helios masters and agents upon which jobs may be
* run.
*/
public interface HeliosDeployment extends AutoCloseable { public interface HeliosDeployment extends AutoCloseable {
/**
* @return A helios client connected to the master(s) of this helios deployment.
*/
HeliosClient client(); HeliosClient client();

/**
* Undeploy (shut down) this Helios deployment.
*/
void close(); void close();
} }


Expand Up @@ -21,9 +21,16 @@


import org.junit.rules.ExternalResource; import org.junit.rules.ExternalResource;


/**
* A HeliosDeploymentResource makes the supplied {@link HeliosDeployment} available to a JUnit
* test, and guarantees to tear it down afterward.
*/
public class HeliosDeploymentResource extends ExternalResource { public class HeliosDeploymentResource extends ExternalResource {
HeliosDeployment deployment; HeliosDeployment deployment;


/**
* @param deployment The Helios deployment to expose to your JUnit tests.
*/
HeliosDeploymentResource(final HeliosDeployment deployment) { HeliosDeploymentResource(final HeliosDeployment deployment) {
this.deployment = deployment; this.deployment = deployment;
} }
Expand All @@ -33,6 +40,11 @@ protected void after() {
deployment.close(); deployment.close();
} }


/**
*
* @return A Helios client connected to the Helios deployment supplied when instantiating the
* HeliosDeploymentResource.
*/
public HeliosClient client() { public HeliosClient client() {
return deployment.client(); return deployment.client();
} }
Expand Down
Expand Up @@ -48,6 +48,11 @@
import static com.google.common.base.Strings.isNullOrEmpty; import static com.google.common.base.Strings.isNullOrEmpty;
import static java.util.Collections.singletonList; import static java.util.Collections.singletonList;


/**
* A HeliosSoloDeployment represents a deployment of Helios Solo, which is to say one Helios
* master and one Helios agent deployed in Docker. Helios Solo uses the Docker instance it is
* deployed to to run its jobs.
*/
public class HeliosSoloDeployment implements HeliosDeployment { public class HeliosSoloDeployment implements HeliosDeployment {


private static final Logger log = LoggerFactory.getLogger(HeliosSoloDeployment.class); private static final Logger log = LoggerFactory.getLogger(HeliosSoloDeployment.class);
Expand Down Expand Up @@ -90,7 +95,7 @@ public class HeliosSoloDeployment implements HeliosDeployment {
heliosHost = dockerHost.address(); heliosHost = dockerHost.address();
} }
this.heliosContainerId = deploySolo(heliosHost); this.heliosContainerId = deploySolo(heliosHost);
heliosPort = getHeliosMasterPort(this.heliosContainerId, HELIOS_MASTER_PORT); heliosPort = getHostPort(this.heliosContainerId, HELIOS_MASTER_PORT);
} catch (HeliosDeploymentException e) { } catch (HeliosDeploymentException e) {
throw new AssertionError("Unable to deploy helios-solo container.", e); throw new AssertionError("Unable to deploy helios-solo container.", e);
} }
Expand Down Expand Up @@ -145,6 +150,10 @@ private List<String> containerBinds() {
return ImmutableList.copyOf(binds); return ImmutableList.copyOf(binds);
} }


/**
* @throws HeliosDeploymentException if we cannot reach the Docker daemon's API from inside a
* probe container.
*/
private void assertDockerReachableFromContainer() throws HeliosDeploymentException { private void assertDockerReachableFromContainer() throws HeliosDeploymentException {
final String probeName = randomString(); final String probeName = randomString();
final HostConfig hostConfig = HostConfig.builder() final HostConfig hostConfig = HostConfig.builder()
Expand Down Expand Up @@ -212,8 +221,15 @@ private List<String> probeCommand(final String probeName) {
return ImmutableList.copyOf(cmd); return ImmutableList.copyOf(cmd);
} }


// TODO(negz): Merge with dockerReachableFromContainer() ? /**
* Predict the gateway IP address for this HeliosSoloDeployment by running and inspecting a
* container.
*
* @return The gateway IP address of the gateway probe container.
* @throws HeliosDeploymentException if the gateway probe container could not be deployed.
*/
private String containerGateway() throws HeliosDeploymentException { private String containerGateway() throws HeliosDeploymentException {
// TODO(negz): Merge with dockerReachableFromContainer() ?
final ContainerConfig containerConfig = ContainerConfig.builder() final ContainerConfig containerConfig = ContainerConfig.builder()
.env(env) .env(env)
.hostConfig(HostConfig.builder().build()) .hostConfig(HostConfig.builder().build())
Expand Down Expand Up @@ -243,6 +259,12 @@ private String containerGateway() throws HeliosDeploymentException {
} }
} }


/**
* @param heliosHost The address at which the Helios agent should expect to find the Helios
* master.
* @return The container ID of the Helios Solo container.
* @throws HeliosDeploymentException if Helios Solo could not be deployed.
*/
private String deploySolo(final String heliosHost) throws HeliosDeploymentException { private String deploySolo(final String heliosHost) throws HeliosDeploymentException {
//TODO(negz): Don't make this.env immutable so early? //TODO(negz): Don't make this.env immutable so early?
final List<String> env = new ArrayList<String>(); final List<String> env = new ArrayList<String>();
Expand Down Expand Up @@ -299,9 +321,17 @@ private void removeContainer(String id) {
} }
} }


private String getHeliosMasterPort(final String containerId, final int port) /**
* Return the first host port bound to the requested container port.
*
* @param containerId The container in which to find the requested port.
* @param containerPort The container port to resolve to a host port.
* @return The first host port bound to the requested container port.
* @throws HeliosDeploymentException when no host port is found.
*/
private String getHostPort(final String containerId, final int containerPort)
throws HeliosDeploymentException { throws HeliosDeploymentException {
final String heliosPort = String.format("%d/tcp", port); final String heliosPort = String.format("%d/tcp", containerPort);
try { try {
final NetworkSettings settings = dockerClient.inspectContainer(containerId).networkSettings(); final NetworkSettings settings = dockerClient.inspectContainer(containerId).networkSettings();
for (Map.Entry<String, List<PortBinding>> entry : settings.ports().entrySet()) { for (Map.Entry<String, List<PortBinding>> entry : settings.ports().entrySet()) {
Expand All @@ -328,28 +358,40 @@ private String randomString() {
return Integer.toHexString(new Random().nextInt()); return Integer.toHexString(new Random().nextInt());
} }


/**
* @return A helios client connected to the master of this HeliosSoloDeployment.
*/
public HeliosClient client() { public HeliosClient client() {
return this.heliosClient; return this.heliosClient;
} }


/**
* Undeploy (shut down) this HeliosSoloDeployment.
*/
public void close() { public void close() {
killContainer(heliosContainerId); killContainer(heliosContainerId);
removeContainer(heliosContainerId); removeContainer(heliosContainerId);
this.dockerClient.close(); this.dockerClient.close();
} }


/**
* @return A Builder that can be used to instantiate a HeliosSoloDeployment.
*/
public static Builder builder() { public static Builder builder() {
return new Builder(); return new Builder();
} }


public static Builder fromEnv() { /**
* @return A Builder with its Docker Client configured automatically using the
* <code>DOCKER_HOST</code> and <code>DOCKER_CERT_PATH</code> environment variables, or sensible
* defaults if they are absent.
*/
public static Builder fromEnv() {
try { try {
DefaultDockerClient.fromEnv().uri(); DefaultDockerClient.fromEnv().uri();
return builder().dockerClient(DefaultDockerClient.fromEnv().build()); return builder().dockerClient(DefaultDockerClient.fromEnv().build());
} catch (DockerCertificateException e) { } catch (DockerCertificateException e) {
// TODO(negz): Just propagate this rather than return null and fail later on checkNotNull? throw new RuntimeException("unable to create Docker client from environment", e);
log.error("unable to create Docker client from environment", e);
return builder();
} }
} }


Expand All @@ -360,31 +402,77 @@ public static class Builder {
private String namespace; private String namespace;
private String heliosUsername; private String heliosUsername;


/**
* Specify a Docker client to be used for this Helios Solo deployment. A Docker client is
* necessary in order to deploy Helios Solo.
*
* @param dockerClient A client connected to the Docker instance in which to deploy Helios Solo.
* @return This Builder, with its Docker client configured.
*/
public Builder dockerClient(final DockerClient dockerClient) { public Builder dockerClient(final DockerClient dockerClient) {
this.dockerClient = dockerClient; this.dockerClient = dockerClient;
return this; return this;
} }


/**
* Optionally specify a DockerHost (i.e. Docker socket and certificate info) to connect to
* Docker from the host OS. If unset the <code>DOCKER_HOST</code> and
* <code>DOCKER_CERT_PATH</code> environment variables will be used. If said variables are not
* present sensible defaults will be used.
*
* @param dockerHost Docker socket and certificate settings for the host OS.
* @return This Builder, with its Docker host configured.
*/
public Builder dockerHost(final DockerHost dockerHost) { public Builder dockerHost(final DockerHost dockerHost) {
this.dockerHost = dockerHost; this.dockerHost = dockerHost;
return this; return this;
} }


/**
* Optionally specify a DockerHost (i.e. Docker socket and certificate info) to connect to
* Docker from inside the Helios container. If unset sensible defaults will be derived from
* the <code>DOCKER_HOST</code> and <code>DOCKER_CERT_PATH</code> environment variables and the
* Docker daemon's configuration.
*
* @param dockerHost Docker socket and certificate settings for the Helios container.
* @return This Builder, with its container Docker host configured.
*/
public Builder containerDockerHost(final DockerHost dockerHost) { public Builder containerDockerHost(final DockerHost dockerHost) {
this.containerDockerHost = containerDockerHost; this.containerDockerHost = containerDockerHost;
return this; return this;
} }


/**
* Optionally specify a unique namespace for the Helios solo agent and Docker container names.
* If unset a random string will be used.
*
* @param namespace A unique namespace for the Helios solo agent and Docker container.
* @return This Builder, with its namespace configured.
*/
public Builder namespace(final String namespace) { public Builder namespace(final String namespace) {
this.namespace = namespace; this.namespace = namespace;
return this; return this;
} }


/**
* Optionally specify the username to be used by the {@link HeliosClient} connected to the
* {@link HeliosSoloDeployment} created with this Builder. If unset a random string will be
* used.
*
* @param username The Helios user to identify as.
* @return This Builder, with its Helios username configured.
*/
public Builder heliosUsername(final String username) { public Builder heliosUsername(final String username) {
this.heliosUsername = username; this.heliosUsername = username;
return this; return this;
} }


/**
* Configures, deploys, and returns a {@link HeliosSoloDeployment} using the as specified by
* this Builder.
*
* @return A Helios Solo deployment configured by this Builder.
*/
public HeliosDeployment build() { public HeliosDeployment build() {
return new HeliosSoloDeployment(this); return new HeliosSoloDeployment(this);
} }
Expand Down

0 comments on commit 8dfca4a

Please sign in to comment.