Skip to content

Commit

Permalink
Merge pull request #115 from iamdanfox/aggressive
Browse files Browse the repository at this point in the history
Integration test verifies AggressiveShutdownStrategy actually works
  • Loading branch information
iamdanfox authored Oct 4, 2016
2 parents 7e1c69a + 0ae550d commit a580343
Show file tree
Hide file tree
Showing 23 changed files with 385 additions and 182 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ public void before() throws IOException, InterruptedException {
@Override
public void after() {
try {
shutdownStrategy().shutdown(dockerCompose());
shutdownStrategy().shutdown(this);
logCollector().stopCollecting();
} catch (IOException | InterruptedException e) {
throw new RuntimeException("Error cleaning up docker compose cluster", e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

package com.palantir.docker.compose.configuration;

import com.palantir.docker.compose.DockerComposeRule;
import com.palantir.docker.compose.execution.AggressiveShutdownStrategy;
import com.palantir.docker.compose.execution.DockerCompose;
import com.palantir.docker.compose.execution.GracefulShutdownStrategy;
import com.palantir.docker.compose.execution.SkipShutdownStrategy;
import java.io.IOException;
Expand All @@ -20,6 +20,6 @@ public interface ShutdownStrategy {
ShutdownStrategy GRACEFUL = new GracefulShutdownStrategy();
ShutdownStrategy SKIP = new SkipShutdownStrategy();

void shutdown(DockerCompose dockerCompose) throws IOException, InterruptedException;
void shutdown(DockerComposeRule rule) throws IOException, InterruptedException;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Copyright 2016 Palantir Technologies, Inc. All rights reserved.
*/

package com.palantir.docker.compose.connection;

import static java.util.stream.Collectors.joining;

import java.util.Arrays;
import org.immutables.value.Value;

@Value.Immutable
public abstract class ContainerName {

public abstract String rawName();

public abstract String semanticName();

@Override
public String toString() {
return semanticName();
}

public static ContainerName fromPsLine(String psLine) {
String[] lineComponents = psLine.split(" ");
String rawName = lineComponents[0];

if (probablyCustomName(rawName)) {
return ImmutableContainerName.builder()
.rawName(rawName)
.semanticName(rawName)
.build();
}

String semanticName = withoutDirectory(withoutScaleNumber(rawName));
return ImmutableContainerName.builder()
.rawName(rawName)
.semanticName(semanticName)
.build();
}

private static boolean probablyCustomName(String rawName) {
return !(rawName.split("_").length >= 3);
}

private static String withoutDirectory(String rawName) {
return Arrays.stream(rawName.split("_"))
.skip(1)
.collect(joining("_"));
}

public static String withoutScaleNumber(String rawName) {
String[] components = rawName.split("_");
return Arrays.stream(components)
.limit(components.length - 1)
.collect(joining("_"));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,98 +16,33 @@
package com.palantir.docker.compose.connection;

import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toList;

import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Stream;

public class ContainerNames implements Iterable<String> {
public class ContainerNames {

private final List<String> containerNames;
private ContainerNames() {}

public ContainerNames(String singleContainerName) {
this(singletonList(singleContainerName));
}

public ContainerNames(List<String> containerNames) {
this.containerNames = containerNames;
}

public static ContainerNames parseFromDockerComposePs(String psOutput) {
String[] splitOnSeparator = psOutput.split("-+\n");
if (splitOnSeparator.length < 2) {
return new ContainerNames(emptyList());
public static List<ContainerName> parseFromDockerComposePs(String psOutput) {
String[] psHeadAndBody = psOutput.split("-+\n");
if (psHeadAndBody.length < 2) {
return emptyList();
}
return new ContainerNames(getContainerNamesAtStartOfLines(splitOnSeparator[1]));
}

private static List<String> getContainerNamesAtStartOfLines(String psContainerOutput) {
return Arrays.stream(psContainerOutput.split("\n"))
.map(String::trim)
.filter(line -> !line.isEmpty())
.map(line -> line.split(" "))
.map(psColumns -> psColumns[0])
.map(withoutDirectory().andThen(withoutScaleNumber()))
.collect(toList());
}

public static Function<String, String> withoutDirectory() {
return fullname -> Arrays.stream(fullname.split("_"))
.skip(1)
.collect(joining("_"));
}

public static Function<String, String> withoutScaleNumber() {
return fullname -> {
final String[] components = fullname.split("_");
return Arrays.stream(components)
.limit(components.length - 1)
.collect(joining("_"));
};
}

@Override
public Iterator<String> iterator() {
return containerNames.iterator();
}

public Stream<String> stream() {
return containerNames.stream();
}

public int size() {
return containerNames.size();
}

@Override
public int hashCode() {
return Objects.hash(containerNames);
}

@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
ContainerNames other = (ContainerNames) obj;
return Objects.equals(containerNames, other.containerNames);
String psBody = psHeadAndBody[1];
return psBodyLines(psBody)
.map(ContainerName::fromPsLine)
.collect(toList());
}

@Override
public String toString() {
return "ContainerNames [containerNames=" + containerNames + "]";
private static Stream<String> psBodyLines(String psBody) {
String[] lines = psBody.split("\n");
return Arrays.stream(lines)
.map(String::trim)
.filter(line -> !line.isEmpty());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,13 @@

package com.palantir.docker.compose.execution;

import static java.util.stream.Collectors.toList;

import com.palantir.docker.compose.DockerComposeRule;
import com.palantir.docker.compose.configuration.ShutdownStrategy;
import com.palantir.docker.compose.connection.ContainerName;
import java.io.IOException;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -18,9 +23,38 @@ public class AggressiveShutdownStrategy implements ShutdownStrategy {
private static final Logger log = LoggerFactory.getLogger(AggressiveShutdownStrategy.class);

@Override
public void shutdown(DockerCompose dockerCompose) throws IOException, InterruptedException {
log.info("Shutting down");
dockerCompose.rm();
public void shutdown(DockerComposeRule rule) throws IOException, InterruptedException {
List<ContainerName> runningContainers = rule.dockerCompose().ps();

log.info("Shutting down {}", runningContainers.stream().map(ContainerName::semanticName).collect(toList()));
if (removeContainersCatchingErrors(rule, runningContainers)) {
return;
}

log.debug("First shutdown attempted failed due to btrfs volume error... retrying");
if (removeContainersCatchingErrors(rule, runningContainers)) {
return;
}

log.warn("Couldn't shut down containers due to btrfs volume error, "
+ "see https://circleci.com/docs/docker-btrfs-error/ for more info.");
}

private boolean removeContainersCatchingErrors(DockerComposeRule rule, List<ContainerName> runningContainers) throws IOException, InterruptedException {
try {
removeContainers(rule, runningContainers);
return true;
} catch (DockerExecutionException exception) {
return false;
}
}

private void removeContainers(DockerComposeRule rule, List<ContainerName> running) throws IOException, InterruptedException {
List<String> rawContainerNames = running.stream()
.map(ContainerName::rawName)
.collect(toList());

rule.docker().rm(rawContainerNames);
log.debug("Finished shutdown");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,14 @@
import com.palantir.docker.compose.configuration.DockerComposeFiles;
import com.palantir.docker.compose.configuration.ProjectName;
import com.palantir.docker.compose.connection.Container;
import com.palantir.docker.compose.connection.ContainerName;
import com.palantir.docker.compose.connection.ContainerNames;
import com.palantir.docker.compose.connection.DockerMachine;
import com.palantir.docker.compose.connection.Ports;
import com.palantir.docker.compose.connection.State;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
import org.apache.commons.io.IOUtils;
import org.joda.time.Duration;
import org.slf4j.Logger;
Expand Down Expand Up @@ -150,7 +152,7 @@ private String[] constructFullDockerComposeRunArguments(DockerComposeRunOption d
}

@Override
public ContainerNames ps() throws IOException, InterruptedException {
public List<ContainerName> ps() throws IOException, InterruptedException {
String psOutput = command.execute(Command.throwingOnError(), "ps");
return ContainerNames.parseFromDockerComposePs(psOutput);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@
package com.palantir.docker.compose.execution;

import com.palantir.docker.compose.connection.Container;
import com.palantir.docker.compose.connection.ContainerNames;
import com.palantir.docker.compose.connection.ContainerName;
import com.palantir.docker.compose.connection.Ports;
import com.palantir.docker.compose.connection.State;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;

abstract class DelegatingDockerCompose implements DockerCompose {
private final DockerCompose dockerCompose;
Expand Down Expand Up @@ -87,7 +88,7 @@ public String run(DockerComposeRunOption dockerComposeRunOption, String containe
}

@Override
public ContainerNames ps() throws IOException, InterruptedException {
public List<ContainerName> ps() throws IOException, InterruptedException {
return dockerCompose.ps();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@
package com.palantir.docker.compose.execution;

import com.palantir.docker.compose.connection.Container;
import com.palantir.docker.compose.connection.ContainerNames;
import com.palantir.docker.compose.connection.ContainerName;
import com.palantir.docker.compose.connection.Ports;
import com.palantir.docker.compose.connection.State;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;

public interface DockerCompose {
void build() throws IOException, InterruptedException;
Expand All @@ -34,7 +35,7 @@ public interface DockerCompose {
void kill(Container container) throws IOException, InterruptedException;
String exec(DockerComposeExecOption dockerComposeExecOption, String containerName, DockerComposeExecArgument dockerComposeExecArgument) throws IOException, InterruptedException;
String run(DockerComposeRunOption dockerComposeRunOption, String containerName, DockerComposeRunArgument dockerComposeRunArgument) throws IOException, InterruptedException;
ContainerNames ps() throws IOException, InterruptedException;
List<ContainerName> ps() throws IOException, InterruptedException;
Container container(String containerName);
boolean writeLogs(String container, OutputStream output) throws IOException;
Ports ports(String service) throws IOException, InterruptedException;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

package com.palantir.docker.compose.execution;

import com.palantir.docker.compose.DockerComposeRule;
import com.palantir.docker.compose.configuration.ShutdownStrategy;
import java.io.IOException;
import org.slf4j.Logger;
Expand All @@ -18,11 +19,11 @@ public class GracefulShutdownStrategy implements ShutdownStrategy {
private static final Logger log = LoggerFactory.getLogger(GracefulShutdownStrategy.class);

@Override
public void shutdown(DockerCompose dockerCompose) throws IOException, InterruptedException {
public void shutdown(DockerComposeRule rule) throws IOException, InterruptedException {
log.debug("Killing docker-compose cluster");
dockerCompose.down();
dockerCompose.kill();
dockerCompose.rm();
rule.dockerCompose().down();
rule.dockerCompose().kill();
rule.dockerCompose().rm();
}

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

import com.palantir.docker.compose.connection.ContainerNames;
import com.palantir.docker.compose.connection.ContainerName;
import java.io.IOException;
import java.util.List;

public class RetryingDockerCompose extends DelegatingDockerCompose {
private final Retryer retryer;
Expand All @@ -39,7 +40,7 @@ public void up() throws IOException, InterruptedException {
}

@Override
public ContainerNames ps() throws IOException, InterruptedException {
public List<ContainerName> ps() throws IOException, InterruptedException {
return retryer.runWithRetries(super::ps);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

package com.palantir.docker.compose.execution;

import com.palantir.docker.compose.DockerComposeRule;
import com.palantir.docker.compose.configuration.ShutdownStrategy;
import java.io.IOException;
import org.slf4j.Logger;
Expand All @@ -14,7 +15,7 @@ public class SkipShutdownStrategy implements ShutdownStrategy {
private static final Logger log = LoggerFactory.getLogger(SkipShutdownStrategy.class);

@Override
public void shutdown(DockerCompose dockerCompose) throws IOException, InterruptedException {
public void shutdown(DockerComposeRule rule) throws IOException, InterruptedException {
log.warn("\n"
+ "******************************************************************************************\n"
+ "* docker-compose-rule has been configured to skip docker-compose shutdown: *\n"
Expand Down
Loading

0 comments on commit a580343

Please sign in to comment.