
com.palantir.docker.compose.execution.ConflictingContainerRemovingDockerCompose Maven / Gradle / Ivy
/*
* (c) Copyright 2016 Palantir Technologies Inc. All rights reserved.
*
* 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.palantir.docker.compose.execution;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSet;
import java.io.IOException;
import java.util.Collection;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ConflictingContainerRemovingDockerCompose extends DelegatingDockerCompose {
private static final Logger log = LoggerFactory.getLogger(ConflictingContainerRemovingDockerCompose.class);
private static final Pattern NAME_CONFLICT_PATTERN = Pattern.compile("name \"([^\"]*)\" is already in use");
private final Docker docker;
private final int retryAttempts;
public ConflictingContainerRemovingDockerCompose(DockerCompose dockerCompose, Docker docker) {
this(dockerCompose, docker, 1);
}
public ConflictingContainerRemovingDockerCompose(DockerCompose dockerCompose, Docker docker, int retryAttempts) {
super(dockerCompose);
Preconditions.checkArgument(retryAttempts >= 1, "retryAttempts must be at least 1, was " + retryAttempts);
this.docker = docker;
this.retryAttempts = retryAttempts;
}
@Override
public void up() throws IOException, InterruptedException {
for (int currRetryAttempt = 0; currRetryAttempt <= retryAttempts; currRetryAttempt++) {
try {
getDockerCompose().up();
return;
} catch (DockerExecutionException e) {
Set conflictingContainerNames = getConflictingContainerNames(e.getMessage());
if (conflictingContainerNames.isEmpty()) {
// failed due to reason other than conflicting containers, so re-throw
throw e;
}
log.debug("docker-compose up failed due to container name conflicts (container names: {}). "
+ "Removing containers and attempting docker-compose up again (attempt {}).",
conflictingContainerNames, currRetryAttempt + 1);
removeContainers(conflictingContainerNames);
}
}
throw new DockerExecutionException("docker-compose up failed");
}
private void removeContainers(Collection containerNames) throws IOException, InterruptedException {
try {
docker.rm(containerNames);
} catch (DockerExecutionException e) {
// there are cases such as in CircleCI where 'docker rm' returns a non-0 exit code and "fails",
// but container is still effectively removed as far as conflict resolution is concerned. Because
// of this, be permissive and do not fail task even if 'rm' fails.
log.debug("docker rm failed, but continuing execution", e);
}
}
Set getConflictingContainerNames(String output) {
ImmutableSet.Builder builder = ImmutableSet.builder();
Matcher matcher = NAME_CONFLICT_PATTERN.matcher(output);
while (matcher.find()) {
builder.add(matcher.group(1));
}
return builder.build();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy