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

org.hortonmachine.modules.docker.DockerHandler Maven / Gradle / Ivy

/*
 * This file is part of HortonMachine (http://www.hortonmachine.org)
 * (C) HydroloGIS - www.hydrologis.com 
 * 
 * The HortonMachine is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see .
 */
package org.hortonmachine.modules.docker;

import java.util.List;

import org.hortonmachine.dbs.utils.OsCheck;
import org.hortonmachine.dbs.utils.OsCheck.OSType;
import org.hortonmachine.gears.libs.exceptions.ModelsRuntimeException;
import org.hortonmachine.gears.libs.modules.HMConstants;
import org.hortonmachine.gears.libs.monitor.IHMProgressMonitor;
import org.hortonmachine.gears.utils.StringUtilities;
import org.joda.time.DateTime;

import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.command.CreateContainerResponse;
import com.github.dockerjava.api.command.ExecCreateCmdResponse;
import com.github.dockerjava.api.command.InspectContainerResponse;
import com.github.dockerjava.api.command.PullImageResultCallback;
import com.github.dockerjava.api.model.Bind;
import com.github.dockerjava.api.model.Image;
import com.github.dockerjava.api.model.PullResponseItem;
import com.github.dockerjava.api.model.ResponseItem.ProgressDetail;
import com.github.dockerjava.api.model.Volume;
import com.github.dockerjava.core.DefaultDockerClientConfig;
import com.github.dockerjava.core.DockerClientBuilder;
import com.github.dockerjava.core.command.ExecStartResultCallback;

@SuppressWarnings("deprecation")
public class DockerHandler {
    public static final String WORKSPACE = "/workspace";

    private static final String MSG_NOTRUNNING = "An error occurred with the docker instance. Is docker running on your machine?";
    private static final String MSG_WIN_SOCKET = "If docker is running, make sure set \n\nExpose daemon on tcp://localhost:2375 without TLS\n\nin the docker General docker Settings.";

    public static final String[] keepAliveCmd = {"sh", "-c", "while :; do sleep 1; done"};

    private DockerClient dockerClient;
    private String containerId;

    /**
     * Checks if a certain image is available.
     * 
     * @param imageName the image to check.
     * @return the id of the image or null.
     */
    public String hasImage( String imageName ) {
        List images = dockerClient.listImagesCmd().withImageNameFilter(imageName).exec();
        if (images.size() > 0) {
            return images.get(0).getId();
        } else {
            return null;
        }
    }

    public void removeImage( String imageId ) {
        dockerClient.removeImageCmd(imageId).exec();
    }

    public void pullImage( String imageName, String tag, IHMProgressMonitor pm ) throws Exception {
        PullImageResultCallback resultCallback = new PullImageResultCallback();
        if (pm != null) {
            resultCallback = new PullImageResultCallback(){
                @Override
                public void onNext( PullResponseItem item ) {
                    String id = item.getId();

                    if (item != null) {
                        ProgressDetail progressDetail = item.getProgressDetail();
                        if (progressDetail != null) {
                            Long currentObj = progressDetail.getCurrent();
                            Long totalObj = progressDetail.getTotal();
                            if (currentObj != null && totalObj != null) {
                                int current = (int) (currentObj / 1000);
                                int total = (int) (totalObj / 1000);
                                String totalUnit = "KB";
                                String currentUnit = "KB";

                                if (total > 1024) {
                                    total = total / 1000;
                                    totalUnit = "MB";
                                }
                                if (current > 1024) {
                                    current = current / 1000;
                                    currentUnit = "MB";
                                }

                                String msg = null;
                                if (current == total) {
                                    msg = "Finished downloading " + id;
                                } else {
                                    msg = "Downloading " + id + " ( " + current + currentUnit + "/" + total + totalUnit + " )";
                                }
                                pm.message(msg);
                            }
                        }
                    }
                    super.onNext(item);
                }
                @Override
                public void onError( Throwable throwable ) {
                    pm.errorMessage("Failed to start pull command:" + throwable.getMessage());
                    super.onError(throwable);
                }
            };
        }
        dockerClient.pullImageCmd(imageName)//
                .withTag(tag)//
                .exec(resultCallback);
        resultCallback.awaitCompletion();
    }

    /**
     * Initialize the docker client. 
     * 
     * @return an error message if there were issues, null if everyhtin gwent smooth.
     */
    public String initDocker() {
        try {
            DefaultDockerClientConfig.Builder builder = DefaultDockerClientConfig.createDefaultConfigBuilder();
            if (OsCheck.getOperatingSystemType() == OSType.Windows) {
                builder.withDockerHost("tcp://localhost:2375");
            }
            dockerClient = DockerClientBuilder.getInstance(builder).build();

            dockerClient.versionCmd().exec();
        } catch (Exception e) {
            String msg = MSG_NOTRUNNING;
            if (OsCheck.getOperatingSystemType() == OSType.Windows) {
                msg += "\n" + MSG_WIN_SOCKET;
            }
            return msg;
        }

        return null;
    }

    public void startContainer( String imageName, String volumePath ) throws Exception {
        if (hasImage(imageName) == null) {
            throw new ModelsRuntimeException(
                    "The image " + imageName + " could not be found your system. Please run the GdalInstaller command first.",
                    this);
        }

//      List containers = dockerClient.listContainersCmd()
//              .withShowSize(true)
//              .withShowAll(true)
//              .withStatusFilter("exited").exec()

        String ts = DateTime.now().toString(HMConstants.dateTimeFormatterYYYYMMDDHHMMSScompact);

        String name = imageName.replace('/', '_').replace(':', '_');

        CreateContainerResponse container;
        if (volumePath != null) {
            Volume v = new Volume(WORKSPACE);
            container = dockerClient.createContainerCmd(imageName)//
                    .withCmd(keepAliveCmd)//
                    .withName(name + ts)//
                    .withWorkingDir(WORKSPACE)//
                    .withBinds(new Bind(volumePath, v))//
                    .exec();
        } else {
            container = dockerClient.createContainerCmd(imageName)//
                    .withCmd(keepAliveCmd)//
                    .withName(name + ts)//
                    .exec();
        }

        containerId = container.getId();
        dockerClient.startContainerCmd(containerId).exec();

        InspectContainerResponse inspectContainerResponse = dockerClient.inspectContainerCmd(containerId).exec();

        if (!inspectContainerResponse.getState().getRunning()) {
            throw new ModelsRuntimeException("Container not running.", this);
        }
    }

    public void execCommand( String command ) throws Exception {
        // Exec command inside running container with attached STDOUT and STDERR
        String[] commandArray = StringUtilities.parseCommand(command);

        ExecCreateCmdResponse execCreateCmdResponse = dockerClient.execCreateCmd(containerId)//
                .withAttachStdout(true) //
                .withAttachStderr(true)//
                .withCmd(commandArray)//
                .withUser("root")//
                .exec();
        dockerClient.execStartCmd(execCreateCmdResponse.getId()).exec(new ExecStartResultCallback(System.out, System.err))
                .awaitCompletion();

//            pm.message(execOutput);

    }

    public void closeClient() throws Exception {
        try {
            if (containerId != null) {
                dockerClient.stopContainerCmd(containerId).withTimeout(2).exec();
                dockerClient.removeContainerCmd(containerId).exec();
            }
        } finally {
            dockerClient.close();
        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy