com.microsoft.azuretools.docker.ui.wizards.publish.AzureSelectDockerWizard.java Source code

Java tutorial

Introduction

Here is the source code for com.microsoft.azuretools.docker.ui.wizards.publish.AzureSelectDockerWizard.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.docker.ui.wizards.publish;

import com.jcraft.jsch.Session;
import com.microsoft.azure.docker.AzureDockerHostsManager;
import com.microsoft.azure.docker.model.AzureDockerImageInstance;
import com.microsoft.azure.docker.model.AzureDockerPreferredSettings;
import com.microsoft.azure.docker.model.DockerHost;
import com.microsoft.azure.docker.model.EditableDockerHost;
import com.microsoft.azure.docker.ops.AzureDockerContainerOps;
import com.microsoft.azure.docker.ops.AzureDockerImageOps;
import com.microsoft.azure.docker.ops.AzureDockerSSHOps;
import com.microsoft.azure.docker.ops.AzureDockerVMOps;
import com.microsoft.azure.docker.ops.utils.AzureDockerUtils;
import com.microsoft.azure.keyvault.KeyVaultClient;
import com.microsoft.azure.management.Azure;
import com.microsoft.azure.management.compute.VirtualMachine;
import com.microsoft.azuretools.authmanage.AuthMethodManager;
import com.microsoft.azuretools.azurecommons.deploy.DeploymentEventArgs;
import com.microsoft.azuretools.azurecommons.deploy.DeploymentEventListener;
import com.microsoft.azuretools.telemetry.AppInsightsClient;
import com.microsoft.azuretools.core.ui.views.AzureDeploymentProgressNotification;
import com.microsoft.azuretools.core.utils.PluginUtil;
import com.microsoft.azuretools.docker.ui.dialogs.AzureInputDockerLoginCredsDialog;
import com.microsoft.azuretools.docker.utils.AzureDockerUIResources;
import com.microsoft.azuretools.sdkmanage.AzureManager;
import com.microsoft.azuretools.utils.AzureUIRefreshCore;
import com.microsoft.azuretools.utils.AzureUIRefreshEvent;
import com.microsoft.tooling.msservices.components.DefaultLoader;

import java.io.File;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.window.Window;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.console.MessageConsole;
import org.eclipse.ui.console.MessageConsoleStream;

public class AzureSelectDockerWizard extends Wizard {
    private static final Logger log = Logger.getLogger(AzureSelectDockerWizard.class.getName());

    private AzureSelectDockerHostPage azureSelectDockerHostPage;
    private AzureConfigureDockerContainerStep azureConfigureDockerContainerStep;

    private IProject project;
    private AzureDockerHostsManager dockerManager;
    private AzureDockerImageInstance dockerImageDescription;

    public AzureSelectDockerWizard(final IProject project, AzureDockerHostsManager dockerManager,
            AzureDockerImageInstance dockerImageDescription) {
        this.project = project;
        this.dockerManager = dockerManager;
        this.dockerImageDescription = dockerImageDescription;

        azureSelectDockerHostPage = new AzureSelectDockerHostPage(this);
        azureConfigureDockerContainerStep = new AzureConfigureDockerContainerStep(this);

        setWindowTitle("Deploying Docker Container on Azure");
    }

    @Override
    public void addPages() {
        addPage(azureSelectDockerHostPage);
        addPage(azureConfigureDockerContainerStep);
    }

    @Override
    public boolean performFinish() {
        return doValidate();
    }

    public boolean doValidate() {
        return azureSelectDockerHostPage.doValidate() && azureConfigureDockerContainerStep.doValidate()
                && (dockerImageDescription.hasNewDockerHost
                        || dockerImageDescription.host.state == DockerHost.DockerHostVMState.RUNNING
                        || DefaultLoader.getUIHelper().showConfirmation(String.format(
                                "The selected Docker host %s state is %s and publishing could fail.\n\n Do you want to continue?",
                                dockerImageDescription.host.name, dockerImageDescription.host.state),
                                "Docker Host Not in Running State", new String[] { "Yes", "No" }, null));
    }

    public AzureDockerImageInstance getDockerImageInstance() {
        return dockerImageDescription;
    }

    public IProject getProject() {
        return project;
    }

    public AzureDockerHostsManager getDockerManager() {
        return dockerManager;
    }

    public void setPredefinedDockerfileOptions(String artifactFileName) {
        if (azureConfigureDockerContainerStep != null) {
            azureConfigureDockerContainerStep.setPredefinedDockerfileOptions(artifactFileName);
        }
    }

    public void setDockerContainerName(String dockerContainerName) {
        if (azureConfigureDockerContainerStep != null) {
            azureConfigureDockerContainerStep.setDockerContainerName(dockerContainerName);
        }
    }

    public void selectDefaultDockerHost(DockerHost dockerHost, boolean selectOtherHosts) {
        if (azureSelectDockerHostPage != null) {
            azureSelectDockerHostPage.selectDefaultDockerHost(dockerHost, selectOtherHosts);
        }
    }

    public String deploy() {
        AzureDockerPreferredSettings dockerPreferredSettings = dockerManager.getDockerPreferredSettings();

        if (dockerPreferredSettings == null) {
            dockerPreferredSettings = new AzureDockerPreferredSettings();
        }

        dockerPreferredSettings.dockerApiName = dockerImageDescription.host.apiUrl;
        dockerPreferredSettings.dockerfileOption = dockerImageDescription.predefinedDockerfile;
        dockerPreferredSettings.region = dockerImageDescription.host.hostVM.region;
        dockerPreferredSettings.vmSize = dockerImageDescription.host.hostVM.vmSize;
        dockerPreferredSettings.vmOS = dockerImageDescription.host.hostOSType.name();
        dockerManager.setDockerPreferredSettings(dockerPreferredSettings);

        DefaultLoader.getIdeHelper().runInBackground(project, "Deploying Docker Container on Azure", false, true,
                "Deploying Web app to a Docker host on Azure...", new Runnable() {
                    @Override
                    public void run() {
                        try {
                            DefaultLoader.getIdeHelper().invokeLater(new Runnable() {
                                @Override
                                public void run() {
                                    if (!dockerImageDescription.hasNewDockerHost) {
                                        Session session = null;

                                        do {
                                            try {
                                                // check if the Docker host is accessible
                                                session = AzureDockerSSHOps
                                                        .createLoginInstance(dockerImageDescription.host);
                                            } catch (Exception e) {
                                                session = null;
                                            }

                                            if (session == null) {
                                                EditableDockerHost editableDockerHost = new EditableDockerHost(
                                                        dockerImageDescription.host);
                                                AzureInputDockerLoginCredsDialog loginCredsDialog = new AzureInputDockerLoginCredsDialog(
                                                        PluginUtil.getParentShell(), project, editableDockerHost,
                                                        dockerManager, false);

                                                if (loginCredsDialog.open() == Window.OK) {
                                                    // Update Docker host log in credentials
                                                    dockerImageDescription.host.certVault = editableDockerHost.updatedDockerHost.certVault;
                                                    dockerImageDescription.host.hasSSHLogIn = editableDockerHost.updatedDockerHost.hasSSHLogIn;
                                                    dockerImageDescription.host.hasPwdLogIn = editableDockerHost.updatedDockerHost.hasPwdLogIn;
                                                    //                                 AzureDockerVMOps.updateDockerHostVM(dockerManager.getSubscriptionsMap().get(dockerImageDescription.sid).azureClient, editableDockerHost.updatedDockerHost);
                                                } else {
                                                    return;
                                                }
                                            }
                                        } while (session == null);
                                    }

                                    //                     Azure azureClient = dockerManager.getSubscriptionsMap().get(dockerImageDescription.sid).azureClient;
                                    //                     DockerContainerDeployTask task = new DockerContainerDeployTask(project, azureClient, dockerImageDescription);
                                    //                     task.queue();
                                    createDockerContainerDeployTask(project, dockerImageDescription, dockerManager);
                                }
                            });
                        } catch (Exception e) {
                            String msg = "An error occurred while attempting to deploy to the selected Docker host."
                                    + "\n" + e.getMessage();
                            PluginUtil.displayErrorDialogWithAzureMsg(PluginUtil.getParentShell(),
                                    "Failed to Deploy Web App as Docker Container", msg, e);
                        }
                    }
                });

        return AzureDockerUtils.getUrl(dockerImageDescription);
    }

    public void createDockerContainerDeployTask(IProject project, AzureDockerImageInstance dockerImageInstance,
            AzureDockerHostsManager dockerManager) {
        String url = AzureDockerUtils.getUrl(dockerImageInstance);

        String deploymentName = url;
        String jobDescription = String.format("Publishing %s as Docker Container",
                new File(dockerImageInstance.artifactPath).getName());
        AzureDeploymentProgressNotification.createAzureDeploymentProgressNotification(deploymentName,
                jobDescription);

        Map<String, String> postEventProperties = new HashMap<String, String>();
        postEventProperties.put("DockerFileOption", dockerImageInstance.predefinedDockerfile);

        Job createDockerHostJob = new Job(jobDescription) {
            @Override
            protected IStatus run(IProgressMonitor progressMonitor) {
                try {
                    // Setup Azure Console and Azure Activity Log Window notifications
                    MessageConsole console = com.microsoft.azuretools.core.Activator
                            .findConsole(com.microsoft.azuretools.core.Activator.CONSOLE_NAME);
                    console.activate();
                    final MessageConsoleStream azureConsoleOut = console.newMessageStream();
                    progressMonitor.beginTask("start task", 100);
                    //                  com.microsoft.azuretools.core.Activator.removeUnNecessaryListener();
                    DeploymentEventListener undeployListnr = new DeploymentEventListener() {
                        @Override
                        public void onDeploymentStep(DeploymentEventArgs args) {
                            progressMonitor.subTask(args.getDeployMessage());
                            progressMonitor.worked(args.getDeployCompleteness());
                            azureConsoleOut
                                    .println(String.format("%s: %s", deploymentName, args.getDeployMessage()));
                        }
                    };
                    com.microsoft.azuretools.core.Activator.getDefault().addDeploymentEventListener(undeployListnr);
                    com.microsoft.azuretools.core.Activator.depEveList.add(undeployListnr);

                    // Start the real job here
                    String msg = String.format("Publishing %s to Docker host %s ...",
                            new File(dockerImageInstance.artifactPath).getName(), dockerImageInstance.host.name);
                    AzureDeploymentProgressNotification.notifyProgress(this, deploymentName, url, 0, msg);

                    msg = "Connecting to Azure...";
                    AzureDeploymentProgressNotification.notifyProgress(this, deploymentName, url, 5, msg);

                    AzureManager azureAuthManager = AuthMethodManager.getInstance().getAzureManager();
                    // not signed in
                    if (azureAuthManager == null) {
                        throw new RuntimeException("User not signed in");
                    }
                    AzureDockerHostsManager dockerManager = AzureDockerHostsManager
                            .getAzureDockerHostsManagerEmpty(azureAuthManager);
                    Azure azureClient = dockerManager.getSubscriptionsMap()
                            .get(dockerImageInstance.host.sid).azureClient;
                    if (progressMonitor.isCanceled()) {
                        displayWarningOnCreateDockerContainerDeployTask(this, progressMonitor, deploymentName);
                        return Status.CANCEL_STATUS;
                    }

                    if (dockerImageInstance.hasNewDockerHost) {
                        msg = String.format("Creating new virtual machine %s ...", dockerImageInstance.host.name);
                        AzureDeploymentProgressNotification.notifyProgress(this, deploymentName, url, 20, msg);
                        AzureDockerUIResources.printDebugMessage(this,
                                "Creating new virtual machine: " + new Date().toString());
                        AzureDockerVMOps.createDockerHostVM(azureClient, dockerImageInstance.host);
                        AzureDockerUIResources.printDebugMessage(this,
                                "Done creating new virtual machine: " + new Date().toString());
                        if (progressMonitor.isCanceled()) {
                            displayWarningOnCreateDockerContainerDeployTask(this, progressMonitor, deploymentName);
                            return Status.CANCEL_STATUS;
                        }

                        msg = String.format("Updating Docker hosts ...");
                        AzureDeploymentProgressNotification.notifyProgress(this, deploymentName, url, 5, msg);
                        AzureDockerUIResources.printDebugMessage(this,
                                "Getting the new docker host details: " + new Date().toString());
                        //                     dockerManager.refreshDockerHostDetails();
                        VirtualMachine vm = azureClient.virtualMachines().getByResourceGroup(
                                dockerImageInstance.host.hostVM.resourceGroupName,
                                dockerImageInstance.host.hostVM.name);
                        if (vm != null) {
                            DockerHost updatedHost = AzureDockerVMOps.getDockerHost(vm,
                                    dockerManager.getDockerVaultsMap());
                            if (updatedHost != null) {
                                dockerImageInstance.host.hostVM = updatedHost.hostVM;
                                dockerImageInstance.host.apiUrl = updatedHost.apiUrl;
                            }
                        }
                        AzureDockerUIResources.printDebugMessage(this,
                                "Done getting new Docker host details: " + new Date().toString());

                        msg = String.format("Waiting for virtual machine to be up %s ...",
                                dockerImageInstance.host.name);
                        AzureDeploymentProgressNotification.notifyProgress(this, deploymentName, url, 10, msg);
                        AzureDockerUIResources.printDebugMessage(this,
                                "Waiting for virtual machine to be up: " + new Date().toString());
                        AzureDockerVMOps.waitForVirtualMachineStartup(azureClient, dockerImageInstance.host);
                        AzureDockerUIResources.printDebugMessage(this,
                                "Done Waiting for virtual machine to be up: " + new Date().toString());
                        if (progressMonitor.isCanceled()) {
                            displayWarningOnCreateDockerContainerDeployTask(this, progressMonitor, deploymentName);
                            return Status.CANCEL_STATUS;
                        }

                        msg = String.format("Configuring Docker service for %s ...", dockerImageInstance.host.name);
                        AzureDeploymentProgressNotification.notifyProgress(this, deploymentName, url, 10, msg);
                        AzureDockerUIResources.printDebugMessage(this,
                                "Configuring Docker host: " + new Date().toString());
                        AzureDockerVMOps.installDocker(dockerImageInstance.host);
                        AzureDockerUIResources.printDebugMessage(this,
                                "Done configuring Docker host: " + new Date().toString());

                        msg = String.format("Updating Docker hosts ...");
                        AzureDeploymentProgressNotification.notifyProgress(this, deploymentName, url, 5, msg);
                        AzureDockerUIResources.printDebugMessage(this,
                                "Refreshing docker hosts: " + new Date().toString());
                        //                     dockerManager.refreshDockerHostDetails();
                        vm = azureClient.virtualMachines().getByResourceGroup(
                                dockerImageInstance.host.hostVM.resourceGroupName,
                                dockerImageInstance.host.hostVM.name);
                        if (vm != null) {
                            DockerHost updatedHost = AzureDockerVMOps.getDockerHost(vm,
                                    dockerManager.getDockerVaultsMap());
                            if (updatedHost != null) {
                                updatedHost.sid = dockerImageInstance.host.sid;
                                updatedHost.hostVM.sid = dockerImageInstance.host.hostVM.sid;
                                if (updatedHost.certVault == null) {
                                    updatedHost.certVault = dockerImageInstance.host.certVault;
                                    updatedHost.hasPwdLogIn = dockerImageInstance.host.hasPwdLogIn;
                                    updatedHost.hasSSHLogIn = dockerImageInstance.host.hasSSHLogIn;
                                    updatedHost.isTLSSecured = dockerImageInstance.host.isTLSSecured;
                                }
                                dockerManager.addDockerHostDetails(updatedHost);
                                if (AzureUIRefreshCore.listeners != null) {
                                    AzureUIRefreshCore.execute(new AzureUIRefreshEvent(
                                            AzureUIRefreshEvent.EventType.ADD, updatedHost));
                                }
                            }
                        }
                        AzureDockerUIResources.printDebugMessage(this,
                                "Done refreshing Docker hosts: " + new Date().toString());
                        AzureDockerUIResources.printDebugMessage(this, "Finished setting up Docker host");
                    } else {
                        msg = String.format("Using virtual machine %s ...", dockerImageInstance.host.name);
                        AzureDeploymentProgressNotification.notifyProgress(this, deploymentName, url, 55, msg);
                    }
                    if (progressMonitor.isCanceled()) {
                        displayWarningOnCreateDockerContainerDeployTask(this, progressMonitor, deploymentName);
                        return Status.CANCEL_STATUS;
                    }

                    if (dockerImageInstance.host.session == null) {
                        AzureDockerUIResources.printDebugMessage(this,
                                "Opening a remote connection to the Docker host: " + new Date().toString());
                        dockerImageInstance.host.session = AzureDockerSSHOps
                                .createLoginInstance(dockerImageInstance.host);
                        AzureDockerUIResources.printDebugMessage(this,
                                "Done opening a remote connection to the Docker host: " + new Date().toString());
                    }

                    if (dockerImageInstance.hasNewDockerHost) {
                        if (dockerImageInstance.host.certVault != null
                                && dockerImageInstance.host.certVault.hostName != null) {
                            AzureDockerUIResources.createDockerKeyVault(dockerImageInstance.host, dockerManager);
                        }
                    }

                    msg = String.format("Uploading Dockerfile and artifact %s on %s ...",
                            dockerImageInstance.artifactName, dockerImageInstance.host.name);
                    AzureDeploymentProgressNotification.notifyProgress(this, deploymentName, url, 15, msg);
                    AzureDockerUIResources.printDebugMessage(this,
                            "Uploading Dockerfile and artifact: " + new Date().toString());
                    AzureDockerVMOps.uploadDockerfileAndArtifact(dockerImageInstance,
                            dockerImageInstance.host.session);
                    AzureDockerUIResources.printDebugMessage(this,
                            "Uploading Dockerfile and artifact: " + new Date().toString());
                    if (progressMonitor.isCanceled()) {
                        displayWarningOnCreateDockerContainerDeployTask(this, progressMonitor, deploymentName);
                        return Status.CANCEL_STATUS;
                    }

                    msg = String.format("Creating Docker image %s on %s ...", dockerImageInstance.dockerImageName,
                            dockerImageInstance.host.name);
                    AzureDeploymentProgressNotification.notifyProgress(this, deploymentName, url, 15, msg);
                    AzureDockerUIResources.printDebugMessage(this,
                            "Creating a Docker image to the Docker host: " + new Date().toString());
                    AzureDockerImageOps.create(dockerImageInstance, dockerImageInstance.host.session);
                    AzureDockerUIResources.printDebugMessage(this,
                            "Done creating a Docker image to the Docker host: " + new Date().toString());
                    if (progressMonitor.isCanceled()) {
                        displayWarningOnCreateDockerContainerDeployTask(this, progressMonitor, deploymentName);
                        return Status.CANCEL_STATUS;
                    }

                    msg = String.format("Creating Docker container %s for image %s on %s ...",
                            dockerImageInstance.dockerContainerName, dockerImageInstance.dockerImageName,
                            dockerImageInstance.host.name);
                    AzureDeploymentProgressNotification.notifyProgress(this, deploymentName, url, 5, msg);
                    AzureDockerUIResources.printDebugMessage(this,
                            "Creating a Docker container to the Docker host: " + new Date().toString());
                    AzureDockerContainerOps.create(dockerImageInstance, dockerImageInstance.host.session);
                    AzureDockerUIResources.printDebugMessage(this,
                            "Done creating a Docker container to the Docker host: " + new Date().toString());
                    if (progressMonitor.isCanceled()) {
                        displayWarningOnCreateDockerContainerDeployTask(this, progressMonitor, deploymentName);
                        return Status.CANCEL_STATUS;
                    }

                    msg = String.format("Starting Docker container %s for image %s on %s ...",
                            dockerImageInstance.dockerContainerName, dockerImageInstance.dockerImageName,
                            dockerImageInstance.host.name);
                    AzureDeploymentProgressNotification.notifyProgress(this, deploymentName, url, 5, msg);
                    AzureDockerUIResources.printDebugMessage(this,
                            "Starting a Docker container to the Docker host: " + new Date().toString());
                    AzureDockerContainerOps.start(dockerImageInstance, dockerImageInstance.host.session);
                    AzureDockerUIResources.printDebugMessage(this,
                            "Done starting a Docker container to the Docker host: " + new Date().toString());
                    if (progressMonitor.isCanceled()) {
                        displayWarningOnCreateDockerContainerDeployTask(this, progressMonitor, deploymentName);
                        return Status.CANCEL_STATUS;
                    }

                    AzureDeploymentProgressNotification.notifyProgress(this, deploymentName, url, 100, "");

                    try {
                        com.microsoft.azuretools.core.Activator.depEveList.remove(undeployListnr);
                        com.microsoft.azuretools.core.Activator.removeDeploymentEventListener(undeployListnr);
                    } catch (Exception ignored) {
                    }
                    progressMonitor.done();
                    AppInsightsClient.create("Deploy as DockerContainer", "", postEventProperties);
                    return Status.OK_STATUS;
                } catch (Exception e) {
                    String msg = "An error occurred while attempting to publish a Docker container!" + "\n"
                            + e.getMessage();
                    log.log(Level.SEVERE, "createDockerContainerDeployTask: " + msg, e);
                    e.printStackTrace();
                    AzureDeploymentProgressNotification.notifyProgress(this, deploymentName, null, -1,
                            "Error: " + e.getMessage());
                    return Status.CANCEL_STATUS;
                }
            }
        };

        createDockerHostJob.schedule();
    }

    private static void displayWarningOnCreateDockerContainerDeployTask(Object parent,
            IProgressMonitor progressMonitor, String deploymentName) {
        DefaultLoader.getIdeHelper().invokeAndWait(new Runnable() {
            @Override
            public void run() {
                Shell shell = PluginUtil.getParentShell();

                if (shell != null) {
                    MessageDialog.openWarning(shell, "Stop Publishing to Docker Container",
                            "Canceling the task at this time can leave the Docker virtual machine host in a broken state and it can resut in publishing to fail the next time!");
                    AzureDeploymentProgressNotification.notifyProgress(parent, deploymentName, "Error", -1,
                            "Stopped by the user");
                    progressMonitor.done();
                }
            }
        });
    }

}