org.wso2.appcloud.core.docker.DockerClient.java Source code

Java tutorial

Introduction

Here is the source code for org.wso2.appcloud.core.docker.DockerClient.java

Source

/*
 *  Copyright (c) 2016, WSO2 Inc. (http://www.wso2.org) 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 org.wso2.appcloud.core.docker;

import com.google.common.base.Strings;
import io.fabric8.docker.client.Config;
import io.fabric8.docker.client.ConfigBuilder;
import io.fabric8.docker.client.DefaultDockerClient;
import io.fabric8.docker.dsl.EventListener;
import io.fabric8.docker.dsl.OutputHandle;
import org.apache.commons.io.FileUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.appcloud.common.AppCloudException;
import org.wso2.appcloud.common.util.AppCloudUtil;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.concurrent.CountDownLatch;

/**
 * Java client for docker operations.
 */
public class DockerClient {

    private static Log log = LogFactory.getLog(DockerClient.class);

    io.fabric8.docker.client.DockerClient dockerClient;
    OutputHandle handle;

    final CountDownLatch buildDone = new CountDownLatch(1);
    final CountDownLatch pushDone = new CountDownLatch(1);
    final CountDownLatch pullDone = new CountDownLatch(1);

    final String TAG_LATEST = "latest";

    public DockerClient() {
        Config config = new ConfigBuilder().withDockerUrl(DockerClientConstants.DEFAULT_DOCKER_URL).build();
        dockerClient = new DefaultDockerClient(config);
    }

    public DockerClient(String uri) {
        Config config = new ConfigBuilder().withDockerUrl(uri)
                .withConnectionTimeout(Integer
                        .parseInt(AppCloudUtil.getPropertyValue(DockerClientConstants.DOCKER_CONNECTION_TIMEOUT)))
                .withRequestTimeout(Integer
                        .parseInt(AppCloudUtil.getPropertyValue(DockerClientConstants.DOCKER_REQUEST_TIMEOUT)))
                .withImagePushTimeout(
                        Integer.parseInt(AppCloudUtil.getPropertyValue(DockerClientConstants.DOCKER_PUSH_TIMEOUT)))
                .withImageBuildTimeout(Integer
                        .parseInt(AppCloudUtil.getPropertyValue(DockerClientConstants.DOCKER_BUILLD_TIMEOUT)))
                .withImageSearchTimeout(Integer
                        .parseInt(AppCloudUtil.getPropertyValue(DockerClientConstants.DOCKER_SEARCH_TIMEOUT)))
                .build();
        dockerClient = new DefaultDockerClient(config);
    }

    /**
     * Create a docker file according to given details. This will get docker template file and replace the parameters
     * with the given customized values in the dockerFilePropertyMap
     * @param dockerFilePath
     * @param runtimeId - application runtime id
     * @param dockerTemplateFilePath
     * @param dockerFileCategory - app creation method eg : svn, url, default
     * @param dockerFilePropertyMap
     * @param customDockerFileProperties
     * @throws IOException
     * @throws AppCloudException
     */
    public void createDockerFile(String dockerFilePath, String runtimeId, String dockerTemplateFilePath,
            String dockerFileCategory, Map<String, String> dockerFilePropertyMap,
            Map<String, String> customDockerFileProperties) throws AppCloudException {

        customDockerFileProperties.keySet().removeAll(dockerFilePropertyMap.keySet());
        dockerFilePropertyMap.putAll(customDockerFileProperties);

        // Get docker template file
        // A sample docker file can be found at
        // https://github.com/wso2/app-cloud/blob/master/modules/resources/dockerfiles/wso2as/default/Dockerfile.wso2as.6.0.0-m1
        String dockerFileTemplatePath = DockerUtil.getDockerFileTemplatePath(runtimeId, dockerTemplateFilePath,
                dockerFileCategory);
        List<String> dockerFileConfigs = new ArrayList<>();

        try {
            for (String line : FileUtils.readLines(new File(dockerFileTemplatePath))) {
                StringTokenizer stringTokenizer = new StringTokenizer(line);
                //Search if line contains keyword to replace with the value
                while (stringTokenizer.hasMoreElements()) {
                    String element = stringTokenizer.nextElement().toString().trim();
                    if (dockerFilePropertyMap.containsKey(element)) {
                        if (log.isDebugEnabled()) {
                            log.debug("Dockerfile placeholder : " + element);
                        }
                        String value = dockerFilePropertyMap.get(element);
                        line = line.replace(element, value);
                    }
                }
                dockerFileConfigs.add(line);
            }
        } catch (IOException e) {
            String msg = "Error occurred while reading docker template file " + dockerFileTemplatePath;
            throw new AppCloudException(msg, e);
        }
        try {
            FileUtils.writeLines(new File(dockerFilePath), dockerFileConfigs);
        } catch (IOException e) {
            String msg = "Error occurred while writing to docker file " + dockerFilePath;
            throw new AppCloudException(msg, e);
        }
    }

    /**
     * Build created docker images
     * @param repoUrl - docker registry url
     * @param imageName - application runtime name
     * @param tag - tag name
     * @param dockerFileUrl - absolute file upload path
     * @throws InterruptedException
     * @throws IOException
     * @throws AppCloudException
     */
    public void buildDockerImage(String repoUrl, String imageName, String tag, String dockerFileUrl)
            throws AppCloudException {

        String dockerImage = repoUrl + "/" + imageName + ":" + tag;
        final boolean[] dockerStatusCheck = new boolean[1];
        dockerStatusCheck[0] = false; //this is to check docker build status, whether it was successful or failed
        try {
            handle = dockerClient.image().build().withRepositoryName(dockerImage).withNoCache()
                    .usingListener(new EventListener() {
                        @Override
                        public void onSuccess(String message) {
                            log.info("Build Success:" + message);
                            buildDone.countDown();
                            dockerStatusCheck[0] = true;
                        }

                        @Override
                        public void onError(String message) {
                            log.error("Build Failure:" + message);
                            buildDone.countDown();
                        }

                        @Override
                        public void onEvent(String event) {
                            log.info(event);
                        }
                    }).fromFolder(dockerFileUrl);
            buildDone.await();
        } catch (InterruptedException e) {
            String msg = "Error occurred while building docker image " + imageName + " with tag : " + tag + " of "
                    + "docker file : " + dockerFileUrl;
            throw new AppCloudException(msg, e);
        } finally {
            try {
                handle.close();
            } catch (IOException e) {
                log.warn("Error occurred while closing output handle after building docker image " + imageName
                        + " with tag : " + tag + " of docker file : " + dockerFileUrl);

            }
        }

        if (!dockerStatusCheck[0]) {
            log.error("Docker image building failed: " + imageName + " repo: " + repoUrl + " docker file: "
                    + dockerFileUrl + " tag: " + tag);
            throw new AppCloudException("Docker image building failed: " + imageName + " repo: " + repoUrl
                    + " docker file: " + dockerFileUrl + " tag: " + tag);
        }
    }

    /**
     * Push docker images
     *
     * @param imageName - application runtime name
     * @param tag       - tag name
     * @throws InterruptedException
     * @throws IOException
     * @throws AppCloudException
     */
    public void pushDockerImage(String imageName, String tag) throws AppCloudException {

        final boolean[] dockerStatusCheck = new boolean[1];
        dockerStatusCheck[0] = false;
        try {
            handle = dockerClient.image().withName(imageName).push().usingListener(new EventListener() {
                @Override
                public void onSuccess(String message) {
                    log.info("Push Success:" + message);
                    pushDone.countDown();
                    dockerStatusCheck[0] = true;
                }

                @Override
                public void onError(String message) {
                    log.error("Push Failure:" + message);
                    pushDone.countDown();
                }

                @Override
                public void onEvent(String event) {
                    log.info(event);
                }
            }).withTag(tag).toRegistry();
            pushDone.await();

        } catch (InterruptedException e) {

            String msg = "Error occurred while pushing docker image " + imageName + " with tag : " + tag + " to "
                    + "docker registry. ";
            log.error(e);
            throw new AppCloudException(msg, e);
        } finally {
            try {
                handle.close();
            } catch (IOException e) {
                log.warn("Error occurred while closing output handle after pushing docker image " + imageName
                        + " with tag : " + tag + " to docker registry. ");
            }
        }

        if (!dockerStatusCheck[0]) {
            log.error("Docker image push failed: " + imageName + " tag: " + tag);
            throw new AppCloudException("Docker image push failed: " + imageName + " tag: " + tag);
        }
    }

    public void pullDockerImage(String imageRepoUrl, String imageTag) throws AppCloudException {

        if (log.isDebugEnabled()) {
            log.debug("Docker image pull triggered for repo : " + imageRepoUrl + " with tag : " + imageTag);
        }

        final boolean[] dockerStatusCheck = new boolean[1];
        dockerStatusCheck[0] = false;
        try {
            handle = dockerClient.image().withName(imageRepoUrl).pull().usingListener(new EventListener() {
                @Override
                public void onSuccess(String message) {
                    log.info("Pull Success:" + message);
                    pullDone.countDown();
                    dockerStatusCheck[0] = true;

                }

                @Override
                public void onError(String message) {
                    log.error("Pull Failure:" + message);
                    pullDone.countDown();
                }

                @Override
                public void onEvent(String event) {
                    log.info(event);
                }
            }).withTag(imageTag).fromRegistry();
            pullDone.await();

        } catch (InterruptedException e) {

            String msg = "Error occurred while pulling docker image " + imageRepoUrl + " with tag : " + imageTag;
            throw new AppCloudException(msg, e);
        } finally {
            try {
                handle.close();
            } catch (IOException e) {
                log.warn("Error occurred while closing output handle after pulling docker image " + imageRepoUrl
                        + " with tag : " + imageTag);
            }
        }

        if (!dockerStatusCheck[0]) {
            log.error("Docker image pull failed : " + imageRepoUrl + " with tag : " + imageTag);
            throw new AppCloudException("Docker image pull failed: " + imageRepoUrl + " with tag : " + imageTag);
        }
    }

    public void tagDockerImage(String oldImage, String oldTag, String newImageName, String newTag)
            throws AppCloudException {

        if (log.isDebugEnabled()) {
            log.debug("Docker image tagging triggered for image : " + oldImage + " with old tag : " + oldTag
                    + " to new " + "tag : " + newImageName);
        }

        boolean dockerStatusCheck = dockerClient.image().withName(oldImage + ":" + oldTag).tag()
                .inRepository(newImageName).withTagName(newTag);
        if (!dockerStatusCheck) {
            log.error("Docker custom image tag failed: " + oldImage);
            throw new AppCloudException("Docker custom image tag failed: " + oldImage);
        }
    }

    public void clientClose() throws IOException {
        dockerClient.close();
    }
}