Bug 471668: Support Docker Machine Connections.
Change-Id: I61bcf2a4134506361b62ec0a1c9bc5712d4787d8
Reviewed-on: https://git.eclipse.org/r/56262
Tested-by: Hudson CI
Reviewed-by: Roland Grunberg <rgrunber@redhat.com>
Tested-by: Roland Grunberg <rgrunber@redhat.com>
diff --git a/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/internal/docker/core/DockerMachine.java b/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/internal/docker/core/DockerMachine.java
new file mode 100644
index 0000000..694b9c7
--- /dev/null
+++ b/containers/org.eclipse.linuxtools.docker.core/src/org/eclipse/linuxtools/internal/docker/core/DockerMachine.java
@@ -0,0 +1,74 @@
+/*******************************************************************************
+ * Copyright (c) 2015 Red Hat.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Red Hat - Initial Contribution
+ *******************************************************************************/
+package org.eclipse.linuxtools.internal.docker.core;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+public class DockerMachine {
+
+ private static final String DM = "docker-machine"; //$NON-NLS-1$
+ private static final String LS = "ls"; //$NON-NLS-1$
+ private static final String URL = "url"; //$NON-NLS-1$
+ private static final String ENV = "env"; //$NON-NLS-1$
+
+ public static String[] getNames() {
+ return call(new String[] { LS, "-q" }); //$NON-NLS-1$
+ }
+
+ public static String getHost(String name) {
+ String[] res = call(new String[] { URL, name });
+ return res.length == 1 ? res[0] : null;
+ }
+
+ public static String getCertPath(String name) {
+ String[] res = getEnv(name);
+ for (String l : res) {
+ if (l.contains("DOCKER_CERT_PATH")) { //$NON-NLS-1$
+ // DOCKER_CERT_PATH="/path/to/cert-folder"
+ return l.split("=")[1].replace("\"", ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+ }
+ return null;
+ }
+
+ private static String[] getEnv(String name) {
+ return call(new String[] { ENV, name });
+ }
+
+ private static String[] call(String[] args) {
+ List<String> result = new ArrayList<>();
+ try {
+ List<String> cmd = new ArrayList<>();
+ cmd.add(DM);
+ cmd.addAll(Arrays.asList(args));
+ Process p = Runtime.getRuntime().exec(cmd.toArray(new String[0]));
+ BufferedReader buff = new BufferedReader(new InputStreamReader(p.getInputStream()));
+ if (p.waitFor(5, TimeUnit.SECONDS) && p.exitValue() == 0) {
+ String line;
+ while ((line = buff.readLine()) != null) {
+ result.add(line);
+ }
+ } else {
+ return new String[0];
+ }
+ } catch (IOException e) {
+ } catch (InterruptedException e) {
+ }
+ return result.toArray(new String[0]);
+ }
+
+}
diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/NewDockerConnectionPage.java b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/NewDockerConnectionPage.java
index 1510389..425166c 100644
--- a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/NewDockerConnectionPage.java
+++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/NewDockerConnectionPage.java
@@ -17,6 +17,8 @@
import java.lang.reflect.InvocationTargetException;
import java.net.URI;
import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.TimeUnit;
@@ -39,17 +41,24 @@
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.jface.viewers.ILabelProviderListener;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.linuxtools.docker.core.DockerConnectionManager;
import org.eclipse.linuxtools.docker.core.DockerException;
+import org.eclipse.linuxtools.docker.core.EnumDockerConnectionSettings;
import org.eclipse.linuxtools.docker.ui.Activator;
import org.eclipse.linuxtools.internal.docker.core.DockerConnection;
import org.eclipse.linuxtools.internal.docker.core.DockerConnection.Builder;
+import org.eclipse.linuxtools.internal.docker.core.DockerMachine;
import org.eclipse.linuxtools.internal.docker.ui.SWTImagesFactory;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
+import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
@@ -59,6 +68,7 @@
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.dialogs.ListDialog;
/**
* {@link WizardPage} to input the settings to connect to a Docker
@@ -216,12 +226,21 @@
GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER)
.applyTo(tcpCertPathBrowseButton);
+ // the 'Search' button
+ final Button searchButton = new Button(container, SWT.NONE);
+ searchButton.setText(WizardMessages
+ .getString("NewDockerConnectionPage.searchButton")); //$NON-NLS-1$
+ GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER)
+ .span(COLUMNS - 1, 1).align(SWT.BEGINNING, SWT.CENTER)
+ .applyTo(searchButton);
+ searchButton.addSelectionListener(onSearchButtonSelection());
+
// the 'test connection' button
final Button testConnectionButton = new Button(container, SWT.NONE);
testConnectionButton.setText(WizardMessages
.getString("NewDockerConnectionPage.testConnection")); //$NON-NLS-1$
GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER)
- .span(COLUMNS, 1).align(SWT.END, SWT.CENTER)
+ .span(1, 1).align(SWT.END, SWT.CENTER)
.applyTo(testConnectionButton);
testConnectionButton
.addSelectionListener(onTestConnectionButtonSelection());
@@ -574,6 +593,67 @@
};
}
+ private SelectionListener onSearchButtonSelection() {
+ return new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ String[] dmNames = DockerMachine.getNames();
+ List<String> activeNames = new ArrayList<>();
+ for (String name : dmNames) {
+ if (DockerMachine.getHost(name) != null) {
+ activeNames.add(name);
+ }
+ }
+ if (activeNames.size() > 0) {
+ ListDialog connPrompt = new ListDialog(getShell());
+ connPrompt.setContentProvider(new ConnectionSelectionContentProvider());
+ connPrompt.setLabelProvider(new ConnectionSelectionLabelProvider());
+ connPrompt.setTitle(WizardMessages.getString(
+ "NewDockerConnectionPage.searchDialog.title")); //$NON-NLS-1$
+ connPrompt.setMessage(WizardMessages.getString(
+ "NewDockerConnectionPage.searchDialog.message")); //$NON-NLS-1$
+ connPrompt.setInput(activeNames.toArray(new String[0]));
+ if (connPrompt.open() == 0 && connPrompt.getResult().length > 0) {
+ String name = ((String) connPrompt.getResult()[0]);
+ String host = DockerMachine.getHost(name);
+ String certPath = DockerMachine.getCertPath(name);
+ model.setBindingMode(EnumDockerConnectionSettings.TCP_CONNECTION);
+ model.setConnectionName(name);
+ model.setUnixSocketPath(null);
+ model.setTcpHost(host);
+ if (certPath != null) {
+ model.setTcpTLSVerify(true);
+ model.setTcpCertPath(certPath);
+ } else {
+ model.setTcpTLSVerify(false);
+ model.setTcpCertPath(null);
+ }
+ }
+ } else {
+ if (dmNames.length > 0) {
+ StringBuffer connections = new StringBuffer();
+ for (String conn : dmNames) {
+ connections.append(", "); //$NON-NLS-1$
+ connections.append(conn);
+ }
+ MessageDialog.openInformation(getShell(),
+ WizardMessages.getString(
+ "NewDockerConnectionPage.searchDialog.discovery.title"), //$NON-NLS-1$
+ WizardMessages.getFormattedString(
+ "NewDockerConnectionPage.searchDialog.discovery.innactive", //$NON-NLS-1$
+ connections.substring(2)));
+ } else {
+ MessageDialog.openInformation(getShell(),
+ WizardMessages.getString(
+ "NewDockerConnectionPage.searchDialog.discovery.title"), //$NON-NLS-1$
+ WizardMessages.getString(
+ "NewDockerConnectionPage.searchDialog.discovery.empty")); //$NON-NLS-1$
+ }
+ }
+ }
+ };
+ }
+
/**
* Opens a new {@link DockerConnection} using the settings of this
* {@link NewDockerConnectionPage}.
@@ -805,4 +885,50 @@
}
+ private class ConnectionSelectionContentProvider
+ implements IStructuredContentProvider {
+ @Override
+ public void inputChanged(Viewer viewer, Object oldInput,
+ Object newInput) {
+ }
+
+ @Override
+ public void dispose() {
+ }
+
+ @Override
+ public Object[] getElements(Object inputElement) {
+ return (String[]) (inputElement);
+ }
+ }
+
+ private class ConnectionSelectionLabelProvider implements ILabelProvider {
+ @Override
+ public void removeListener(ILabelProviderListener listener) {
+ }
+
+ @Override
+ public boolean isLabelProperty(Object element, String property) {
+ return false;
+ }
+
+ @Override
+ public void dispose() {
+ }
+
+ @Override
+ public void addListener(ILabelProviderListener listener) {
+ }
+
+ @Override
+ public String getText(Object element) {
+ return element.toString();
+ }
+
+ @Override
+ public Image getImage(Object element) {
+ return SWTImagesFactory.DESC_REPOSITORY_MIDDLE.createImage();
+ }
+ }
+
}
diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/WizardMessages.properties b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/WizardMessages.properties
index 41d0f7d..fefc3aa 100644
--- a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/WizardMessages.properties
+++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/wizards/WizardMessages.properties
@@ -164,6 +164,7 @@
NewDockerConnectionPage.tcpPathLabel=Path:
NewDockerConnectionPage.tcpPathTooltip=Path to the certificates folder
NewDockerConnectionPage.testConnection=Test Connection
+NewDockerConnectionPage.searchButton=Search
NewDockerConnectionPage.retrieveTask=Retrieving Docker connection settings...
NewDockerConnectionPage.pingTask=Pinging Docker daemon...
NewDockerConnectionPage.success=Success
@@ -187,6 +188,11 @@
NewDockerConnectionPage.validation.missingTcpCertPath.msg=Path to TCP connection certificates is missing
NewDockerConnectionPage.validation.invalidTcpCertPath.msg=Path to TCP connection certificates is invalid
NewDockerConnectionPage.validation.unreadableTcpCertPath.msg=Path to TCP connection certificates is not readable
+NewDockerConnectionPage.searchDialog.title=Docker Connection Selection
+NewDockerConnectionPage.searchDialog.message=Select the connection to create.
+NewDockerConnectionPage.searchDialog.discovery.title=Connection Discovery
+NewDockerConnectionPage.searchDialog.discovery.empty=No connections were found.
+NewDockerConnectionPage.searchDialog.discovery.innactive="Discovered connection(s): {0} but none are active."
ImageSearch.title=Search and pull a Docker image
ImageSearchPage.title=Search the Docker Registry for images