Skip to content

Commit

Permalink
Merge pull request #55 from iamdanfox/improved-builder
Browse files Browse the repository at this point in the history
Improved builder idea
  • Loading branch information
joelea committed Apr 29, 2016
2 parents 75830de + 4916c57 commit 84e2f7e
Show file tree
Hide file tree
Showing 13 changed files with 386 additions and 109 deletions.
153 changes: 153 additions & 0 deletions src/main/java/com/palantir/docker/compose/DockerComposeRule.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
/*
* Copyright 2016 Palantir Technologies, Inc. All rights reserved.
*/
package com.palantir.docker.compose;

import com.palantir.docker.compose.configuration.DockerComposeFiles;
import com.palantir.docker.compose.configuration.ProjectName;
import com.palantir.docker.compose.connection.Cluster;
import com.palantir.docker.compose.connection.ContainerCache;
import com.palantir.docker.compose.connection.DockerMachine;
import com.palantir.docker.compose.connection.waiting.ClusterWait;
import com.palantir.docker.compose.connection.waiting.MultiServiceHealthCheck;
import com.palantir.docker.compose.connection.waiting.MultiServiceWait;
import com.palantir.docker.compose.connection.waiting.SingleServiceHealthCheck;
import com.palantir.docker.compose.connection.waiting.SingleServiceWait;
import com.palantir.docker.compose.execution.DefaultDockerCompose;
import com.palantir.docker.compose.execution.DockerCompose;
import com.palantir.docker.compose.execution.DockerComposeExecArgument;
import com.palantir.docker.compose.execution.DockerComposeExecOption;
import com.palantir.docker.compose.execution.DockerComposeExecutable;
import com.palantir.docker.compose.execution.RetryingDockerCompose;
import com.palantir.docker.compose.logging.DoNothingLogCollector;
import com.palantir.docker.compose.logging.FileLogCollector;
import com.palantir.docker.compose.logging.LogCollector;
import java.io.IOException;
import java.util.List;
import org.immutables.value.Value;
import org.joda.time.Duration;
import org.junit.rules.ExternalResource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Value.Immutable
@Value.Style(depluralize = true)
public abstract class DockerComposeRule extends ExternalResource {
public static final Duration DEFAULT_TIMEOUT = Duration.standardMinutes(2);
public static final int DEFAULT_RETRY_ATTEMPTS = 2;

private static final Logger log = LoggerFactory.getLogger(DockerComposeRule.class);

public abstract DockerComposeFiles files();

protected abstract List<ClusterWait> clusterWaits();

@Value.Default
public DockerMachine machine() {
return DockerMachine.localMachine().build();
}

@Value.Default
public ProjectName projectName() {
return ProjectName.random();
}

@Value.Default
public DockerComposeExecutable executable() {
return DockerComposeExecutable.builder()
.dockerComposeFiles(files())
.dockerConfiguration(machine())
.projectName(projectName())
.build();
}

@Value.Default
public DockerCompose dockerCompose() {
DockerCompose dockerCompose = new DefaultDockerCompose(executable(), machine());
return new RetryingDockerCompose(retryAttempts(), dockerCompose);
}

@Value.Default
public Cluster containers() {
return new ContainerCache(dockerCompose());
}

@Value.Default
protected int retryAttempts() {
return DEFAULT_RETRY_ATTEMPTS;
}

@Value.Default
protected LogCollector logCollector() {
return new DoNothingLogCollector();
}

@Override
public void before() throws IOException, InterruptedException {
log.debug("Starting docker-compose cluster");
dockerCompose().build();
dockerCompose().up();

log.debug("Starting log collection");

logCollector().startCollecting(dockerCompose());
log.debug("Waiting for services");
clusterWaits().forEach(clusterWait -> clusterWait.waitUntilReady(containers()));
log.debug("docker-compose cluster started");
}

@Override
public void after() {
try {
log.debug("Killing docker-compose cluster");
dockerCompose().down();
dockerCompose().kill();
dockerCompose().rm();
logCollector().stopCollecting();
} catch (IOException | InterruptedException e) {
throw new RuntimeException("Error cleaning up docker compose cluster", e);
}
}

public void exec(DockerComposeExecOption options, String containerName,
DockerComposeExecArgument arguments) throws IOException, InterruptedException {
dockerCompose().exec(options, containerName, arguments);
}

public static ImmutableDockerComposeRule.Builder builder() {
return ImmutableDockerComposeRule.builder();
}

public abstract static class Builder {

public abstract ImmutableDockerComposeRule.Builder files(DockerComposeFiles files);

public ImmutableDockerComposeRule.Builder file(String dockerComposeYmlFile) {
return files(DockerComposeFiles.from(dockerComposeYmlFile));
}

public abstract ImmutableDockerComposeRule.Builder logCollector(LogCollector logCollector);

public ImmutableDockerComposeRule.Builder saveLogsTo(String path) {
return logCollector(FileLogCollector.fromPath(path));
}

public abstract ImmutableDockerComposeRule.Builder addClusterWait(ClusterWait clusterWait);

public ImmutableDockerComposeRule.Builder waitingForService(String serviceName, SingleServiceHealthCheck healthCheck) {
return addClusterWait(SingleServiceWait.of(serviceName, healthCheck, DEFAULT_TIMEOUT));
}

public ImmutableDockerComposeRule.Builder waitingForService(String serviceName, SingleServiceHealthCheck healthCheck, Duration timeout) {
return addClusterWait(SingleServiceWait.of(serviceName, healthCheck, timeout));
}

public ImmutableDockerComposeRule.Builder waitingForServices(List<String> services, MultiServiceHealthCheck healthCheck) {
return addClusterWait(MultiServiceWait.of(services, healthCheck, DEFAULT_TIMEOUT));
}

public ImmutableDockerComposeRule.Builder waitingForServices(List<String> services, MultiServiceHealthCheck healthCheck, Duration timeout) {
return addClusterWait(MultiServiceWait.of(services, healthCheck, timeout));
}
}
}
80 changes: 25 additions & 55 deletions src/main/java/com/palantir/docker/compose/DockerComposition.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,108 +15,78 @@
*/
package com.palantir.docker.compose;

import com.google.common.collect.ImmutableList;
import com.palantir.docker.compose.configuration.DockerComposeFiles;
import com.palantir.docker.compose.configuration.ProjectName;
import com.palantir.docker.compose.connection.ContainerCache;
import com.palantir.docker.compose.connection.DockerMachine;
import com.palantir.docker.compose.connection.DockerPort;
import com.palantir.docker.compose.connection.waiting.ServiceWait;
import com.palantir.docker.compose.execution.DefaultDockerCompose;
import com.palantir.docker.compose.execution.DockerCompose;
import com.palantir.docker.compose.execution.DockerComposeExecArgument;
import com.palantir.docker.compose.execution.DockerComposeExecOption;
import com.palantir.docker.compose.logging.LogCollector;
import java.io.IOException;
import java.util.List;
import org.junit.rules.ExternalResource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class DockerComposition extends ExternalResource {

private static final Logger log = LoggerFactory.getLogger(DockerComposition.class);

private final DockerCompose dockerCompose;
private final ContainerCache containers;
private final List<ServiceWait> serviceWaits;
private final LogCollector logCollector;

public DockerComposition(
DockerCompose dockerCompose,
List<ServiceWait> serviceWaits,
LogCollector logCollector,
ContainerCache containers) {
this.dockerCompose = dockerCompose;
this.serviceWaits = ImmutableList.copyOf(serviceWaits);
this.logCollector = logCollector;
this.containers = containers;
private DockerComposeRule rule;

public DockerComposition(DockerComposeRule rule) {
this.rule = rule;
}

@Override
public void before() throws IOException, InterruptedException {
log.debug("Starting docker-compose cluster");
dockerCompose.build();
dockerCompose.up();

log.debug("Starting log collection");

logCollector.startCollecting(dockerCompose);
log.debug("Waiting for services");
serviceWaits.forEach(ServiceWait::waitTillServiceIsUp);
log.debug("docker-compose cluster started");
rule.before();
}

@Override
public void after() {
try {
log.debug("Killing docker-compose cluster");
dockerCompose.down();
dockerCompose.kill();
dockerCompose.rm();
logCollector.stopCollecting();
} catch (IOException | InterruptedException e) {
throw new RuntimeException("Error cleaning up docker compose cluster", e);
}
rule.after();
}

public DockerPort portOnContainerWithExternalMapping(String container, int portNumber) throws IOException, InterruptedException {
return containers.get(container)
.portMappedExternallyTo(portNumber);
return rule.containers().container(container).portMappedExternallyTo(portNumber);
}

public DockerPort portOnContainerWithInternalMapping(String container, int portNumber) throws IOException, InterruptedException {
return containers.get(container)
.portMappedInternallyTo(portNumber);
return rule.containers().container(container).portMappedInternallyTo(portNumber);
}

public static DockerCompositionBuilder of(String dockerComposeFile) {
return of(DockerComposeFiles.from(dockerComposeFile));
return new DockerCompositionBuilder()
.files(DockerComposeFiles.from(dockerComposeFile));
}

public static DockerCompositionBuilder of(DockerComposeFiles dockerComposeFiles) {
return of(dockerComposeFiles, DockerMachine.localMachine().build());
return new DockerCompositionBuilder()
.files(dockerComposeFiles);
}

public static DockerCompositionBuilder of(String dockerComposeFile, DockerMachine dockerMachine) {
return of(DockerComposeFiles.from(dockerComposeFile), dockerMachine);
return new DockerCompositionBuilder()
.files(DockerComposeFiles.from(dockerComposeFile))
.machine(dockerMachine);
}

public static DockerCompositionBuilder of(DockerComposeFiles dockerComposeFiles, DockerMachine dockerMachine) {
return of(new DefaultDockerCompose(dockerComposeFiles, dockerMachine, ProjectName.random()));
return new DockerCompositionBuilder()
.files(dockerComposeFiles)
.machine(dockerMachine);
}

public static DockerCompositionBuilder of(DockerComposeFiles dockerComposeFiles, DockerMachine dockerMachine, String projectName) {
return of(new DefaultDockerCompose(dockerComposeFiles, dockerMachine, ProjectName.fromString(projectName)));
return new DockerCompositionBuilder()
.files(dockerComposeFiles)
.machine(dockerMachine)
.projectName(ProjectName.fromString(projectName));
}

public static DockerCompositionBuilder of(DockerCompose executable) {
return new DockerCompositionBuilder(executable);
public static DockerCompositionBuilder of(DockerCompose compose) {
return new DockerCompositionBuilder().dockerCompose(compose);
}

public void exec(DockerComposeExecOption options, String containerName, DockerComposeExecArgument arguments)
throws IOException, InterruptedException {
dockerCompose.exec(options, containerName, arguments);
rule.exec(options, containerName, arguments);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,71 +15,75 @@
*/
package com.palantir.docker.compose;

import static java.util.stream.Collectors.toList;
import static org.joda.time.Duration.standardMinutes;

import com.palantir.docker.compose.connection.Container;
import com.palantir.docker.compose.connection.ContainerCache;
import com.palantir.docker.compose.ImmutableDockerComposeRule.Builder;
import com.palantir.docker.compose.configuration.DockerComposeFiles;
import com.palantir.docker.compose.configuration.ProjectName;
import com.palantir.docker.compose.connection.DockerMachine;
import com.palantir.docker.compose.connection.waiting.MultiServiceHealthCheck;
import com.palantir.docker.compose.connection.waiting.ServiceWait;
import com.palantir.docker.compose.connection.waiting.SingleServiceHealthCheck;
import com.palantir.docker.compose.execution.DockerCompose;
import com.palantir.docker.compose.execution.RetryingDockerCompose;
import com.palantir.docker.compose.logging.DoNothingLogCollector;
import com.palantir.docker.compose.logging.FileLogCollector;
import com.palantir.docker.compose.logging.LogCollector;
import java.util.ArrayList;
import java.util.List;
import org.joda.time.Duration;

public class DockerCompositionBuilder {
private static final Duration DEFAULT_TIMEOUT = standardMinutes(2);
public static final int DEFAULT_RETRY_ATTEMPTS = 2;

private final List<ServiceWait> serviceWaits = new ArrayList<>();
private final DockerCompose dockerCompose;
private final ContainerCache containers;
private LogCollector logCollector = new DoNothingLogCollector();
private int numRetryAttempts = DEFAULT_RETRY_ATTEMPTS;
private final Builder builder;

public DockerCompositionBuilder(DockerCompose dockerCompose) {
this.dockerCompose = dockerCompose;
this.containers = new ContainerCache(dockerCompose);
public DockerCompositionBuilder() {
this.builder = DockerComposeRule.builder();
}

public DockerCompositionBuilder waitingForService(String serviceName, SingleServiceHealthCheck check) {
return waitingForService(serviceName, check, DEFAULT_TIMEOUT);
builder.waitingForService(serviceName, check);
return this;
}

public DockerCompositionBuilder waitingForServices(List<String> services, MultiServiceHealthCheck check) {
return waitingForServices(services, check, DEFAULT_TIMEOUT);
builder.waitingForServices(services, check);
return this;
}

public DockerCompositionBuilder waitingForServices(List<String> services, MultiServiceHealthCheck check, Duration timeout) {
List<Container> containersToWaitFor = services.stream()
.map(containers::get)
.collect(toList());
serviceWaits.add(new ServiceWait(containersToWaitFor, check, timeout));
builder.waitingForServices(services, check, timeout);
return this;
}

public DockerCompositionBuilder waitingForService(String serviceName, SingleServiceHealthCheck check, Duration timeout) {
serviceWaits.add(new ServiceWait(containers.get(serviceName), check, timeout));
builder.waitingForService(serviceName, check, timeout);
return this;
}

public DockerCompositionBuilder files(DockerComposeFiles files) {
builder.files(files);
return this;
}

public DockerCompositionBuilder machine(DockerMachine machine) {
builder.machine(machine);
return this;
}

public DockerCompositionBuilder projectName(ProjectName name) {
builder.projectName(name);
return this;
}

public DockerCompositionBuilder dockerCompose(DockerCompose compose) {
builder.dockerCompose(compose);
return this;
}

public DockerCompositionBuilder saveLogsTo(String path) {
this.logCollector = FileLogCollector.fromPath(path);
builder.saveLogsTo(path);
return this;
}

public DockerCompositionBuilder retryAttempts(int retryAttempts) {
this.numRetryAttempts = retryAttempts;
builder.retryAttempts(retryAttempts);
return this;
}

public DockerComposition build() {
DockerCompose retryingDockerCompose = new RetryingDockerCompose(numRetryAttempts, dockerCompose);
return new DockerComposition(retryingDockerCompose, serviceWaits, logCollector, containers);
DockerComposeRule rule = builder.build();
return new DockerComposition(rule);
}
}
Loading

0 comments on commit 84e2f7e

Please sign in to comment.