All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.palantir.docker.compose.execution.ConflictingContainerRemovingDockerCompose Maven / Gradle / Ivy

There is a newer version: 2.3.0
Show newest version
/*
 * (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