com.microsoft.azuretools.container.handlers.DockerRunHandler.java Source code

Java tutorial

Introduction

Here is the source code for com.microsoft.azuretools.container.handlers.DockerRunHandler.java

Source

/**
 * Copyright (c) Microsoft Corporation
 *
 * All rights reserved.
 *
 * MIT License
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
 * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
 * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of
 * the Software.
 *
 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
 * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package com.microsoft.azuretools.container.handlers;

import com.microsoft.azuretools.container.ConsoleLogger;
import com.microsoft.azuretools.container.Constant;
import com.microsoft.azuretools.container.Runtime;
import com.microsoft.azuretools.core.utils.AzureAbstractHandler;
import com.microsoft.azuretools.core.utils.PluginUtil;
import com.microsoft.tooling.msservices.components.DefaultLoader;
import com.spotify.docker.client.DefaultDockerClient.Builder;
import com.spotify.docker.client.DockerClient;
import com.spotify.docker.client.ProgressHandler;
import com.spotify.docker.client.exceptions.DockerCertificateException;
import com.spotify.docker.client.exceptions.DockerException;
import com.spotify.docker.client.messages.Container;
import com.spotify.docker.client.messages.ContainerConfig;
import com.spotify.docker.client.messages.ContainerCreation;
import com.spotify.docker.client.messages.HostConfig;
import com.spotify.docker.client.messages.PortBinding;
import com.spotify.docker.client.messages.ProgressMessage;

import java.io.IOException;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicReference;

import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jst.j2ee.datamodel.properties.IJ2EEComponentExportDataModelProperties;
import org.eclipse.jst.j2ee.internal.web.archive.operations.WebComponentExportDataModelProvider;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.handlers.HandlerUtil;
import org.eclipse.wst.common.frameworks.datamodel.DataModelFactory;
import org.eclipse.wst.common.frameworks.datamodel.IDataModel;

public class DockerRunHandler extends AzureAbstractHandler {

    @Override
    public Object onExecute(ExecutionEvent event) throws ExecutionException {
        IWorkbenchWindow window = HandlerUtil.getActiveWorkbenchWindowChecked(event);
        IProject project = PluginUtil.getSelectedProject();

        if (project == null) {
            ConsoleLogger.error(Constant.ERROR_NO_SELECTED_PROJECT);
            return null;
        }

        String destinationPath = project.getLocation() + Constant.DOCKER_CONTEXT_FOLDER + project.getName()
                + ".war";
        final DockerClient docker;

        try {
            // Initialize docker client according to env DOCKER_HOST & DOCKER_CERT_PATH
            ConsoleLogger.info(Constant.MESSAGE_DOCKER_CONNECTING);
            Builder dockerBuilder = Runtime.getInstance().getDockerBuilder();
            docker = dockerBuilder.build();
            // Stop running container
            String runningContainerId = Runtime.getInstance().getRunningContainerId();
            if (containerExists(docker, runningContainerId)) {
                boolean stop = MessageDialog.openConfirm(window.getShell(), "Stop",
                        Constant.MESSAGE_CONFIRM_STOP_CONTAINER);
                if (stop) {
                    Runtime.getInstance().cleanRuningContainer();
                } else {
                    return null;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            ConsoleLogger.error(String.format(Constant.ERROR_RUNNING_DOCKER, e.getMessage()));
            return null;
        }

        DefaultLoader.getIdeHelper().runInBackground(project, Constant.MESSAGE_EXECUTE_DOCKER_RUN, true, true,
                Constant.MESSAGE_EXECUTE_DOCKER_RUN, () -> {
                    try {
                        // export WAR file
                        DefaultLoader.getIdeHelper().invokeAndWait(() -> {
                            ConsoleLogger.info(String.format(Constant.MESSAGE_EXPORTING_PROJECT, destinationPath));
                        });
                        export(project, destinationPath);

                        // build image based on WAR file
                        DefaultLoader.getIdeHelper().invokeAndWait(() -> {
                            ConsoleLogger.info(Constant.MESSAGE_BUILDING_IMAGE);
                        });
                        String imageName = build(docker, project,
                                project.getLocation() + Constant.DOCKER_CONTEXT_FOLDER);
                        DefaultLoader.getIdeHelper().invokeAndWait(() -> {
                            ConsoleLogger.info(String.format(Constant.MESSAGE_IMAGE_INFO, imageName));
                        });

                        // create a container
                        String containerId = createContainer(docker, project, imageName);
                        DefaultLoader.getIdeHelper().invokeAndWait(() -> {
                            ConsoleLogger.info(Constant.MESSAGE_CREATING_CONTAINER);
                            ConsoleLogger.info(String.format(Constant.MESSAGE_CONTAINER_INFO, containerId));
                        });

                        // start container
                        DefaultLoader.getIdeHelper().invokeAndWait(() -> {
                            ConsoleLogger.info(Constant.MESSAGE_STARTING_CONTAINER);
                        });
                        String webappUrl = runContainer(docker, containerId);
                        DefaultLoader.getIdeHelper().invokeAndWait(() -> {
                            ConsoleLogger.info(String.format(Constant.MESSAGE_CONTAINER_STARTED, webappUrl,
                                    project.getName()));
                        });
                    } catch (Exception e) {
                        e.printStackTrace();
                        DefaultLoader.getIdeHelper().invokeAndWait(() -> {
                            ConsoleLogger.error(String.format(Constant.ERROR_RUNNING_DOCKER, e.getMessage()));
                        });
                    }
                });
        return null;
    }

    private String createContainer(DockerClient docker, IProject project, String imageName)
            throws DockerException, InterruptedException {
        final Map<String, List<PortBinding>> portBindings = new HashMap<>();
        List<PortBinding> randomPort = new ArrayList<>();
        PortBinding randomBinding = PortBinding.randomPort("0.0.0.0");
        randomPort.add(randomBinding);
        portBindings.put(Constant.TOMCAT_SERVICE_PORT, randomPort);

        final HostConfig hostConfig = HostConfig.builder().portBindings(portBindings).build();

        final ContainerConfig config = ContainerConfig.builder().hostConfig(hostConfig).image(imageName)
                .exposedPorts(Constant.TOMCAT_SERVICE_PORT).build();
        final ContainerCreation container = docker.createContainer(config);
        return container.id();
    }

    private String runContainer(DockerClient docker, String containerId) throws Exception {
        docker.startContainer(containerId);
        final List<Container> containers = docker.listContainers();
        final Optional<Container> res = containers.stream().filter(item -> item.id().equals(containerId))
                .findFirst();

        if (res.isPresent()) {
            Runtime.getInstance().setRunningContainerId(res.get().id());
            return String.format("http://%s:%s", docker.getHost(), res.get().ports().stream()
                    .filter(item -> item.privatePort().equals(8080)).findFirst().get().publicPort());
        } else {
            String errorMsg = String.format(Constant.ERROR_STARTING_CONTAINER, containerId);
            ConsoleLogger.error(errorMsg);
            throw new Exception(errorMsg);
        }
    }

    private String build(DockerClient docker, IProject project, String dockerDirectory)
            throws DockerCertificateException, DockerException, InterruptedException, IOException {
        final AtomicReference<String> imageIdFromMessage = new AtomicReference<>();
        final String imageName = String.format("%s-%s:%tY%<tm%<td%<tH%<tM%<tS", Constant.IMAGE_PREFIX,
                project.getName().toLowerCase(), new java.util.Date());
        docker.build(Paths.get(dockerDirectory), imageName, new ProgressHandler() {
            @Override
            public void progress(ProgressMessage message) throws DockerException {
                final String imageId = message.buildImageId();
                if (imageId != null) {
                    imageIdFromMessage.set(imageId);
                }
            }
        });
        return imageName;
    }

    private void export(IProject project, String destinationPath) throws Exception {
        String projectName = project.getName();
        project.build(IncrementalProjectBuilder.FULL_BUILD, null);
        IDataModel dataModel = DataModelFactory.createDataModel(new WebComponentExportDataModelProvider());
        dataModel.setProperty(IJ2EEComponentExportDataModelProperties.PROJECT_NAME, projectName);
        dataModel.setProperty(IJ2EEComponentExportDataModelProperties.ARCHIVE_DESTINATION, destinationPath);
        dataModel.getDefaultOperation().execute(null, null);
    }

    private boolean containerExists(DockerClient docker, String containerId)
            throws DockerException, InterruptedException {
        long count = docker.listContainers().stream().filter(item -> item.id().equals(containerId)).count();
        return (count > 0);
    }
}