Skip to content
This repository was archived by the owner on Jan 11, 2019. It is now read-only.

Commit 961a1f7

Browse files
author
amccaskey
committed
Pushing DockerClientFactory.
This commit introduces a DockerClientFactory that eases the creation of the DockerClient. It handles a few things that are OS specific. Signed-off-by: amccaskey <[email protected]>
1 parent f032590 commit 961a1f7

File tree

9 files changed

+271
-17
lines changed

9 files changed

+271
-17
lines changed

org.eclipse.ice.item.test/META-INF/MANIFEST.MF

+3-2
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@ Bundle-SymbolicName: org.eclipse.ice.item.test
55
Bundle-Version: 2.1.8.20160208
66
Fragment-Host: org.eclipse.ice.item;bundle-version="1.0.0"
77
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
8-
Import-Package: org.eclipse.ice.core.iCore,
8+
Import-Package: com.spotify.docker.client,
9+
org.eclipse.eavp.viz.service.mesh.datastructures,
10+
org.eclipse.ice.core.iCore,
911
org.eclipse.ice.datastructures.entry,
1012
org.eclipse.ice.io.serializable,
1113
org.eclipse.ice.item,
1214
org.eclipse.ice.item.action,
1315
org.eclipse.ice.persistence.xml,
14-
org.eclipse.eavp.viz.service.mesh.datastructures,
1516
org.osgi.framework;version="1.6.0"
1617
Require-Bundle: org.junit;bundle-version="4.8.1"
1718
Bundle-Vendor: Oak Ridge National Laboratory
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package org.eclipse.ice.item.test;
2+
3+
import static org.junit.Assert.assertNotNull;
4+
import static org.junit.Assert.assertTrue;
5+
import static org.junit.Assert.fail;
6+
7+
import java.io.IOException;
8+
9+
import org.eclipse.ice.item.jobLauncher.DockerClientFactory;
10+
import org.junit.Before;
11+
import org.junit.Test;
12+
13+
import com.spotify.docker.client.DockerCertificateException;
14+
import com.spotify.docker.client.DockerClient;
15+
16+
/**
17+
* This class tests the DockerClientFactory.
18+
*
19+
* @author Alex McCaskey
20+
*
21+
*/
22+
public class DockerClientFactoryTester {
23+
24+
/**
25+
* This flag triggers the test if Docker has been found
26+
* on the system.
27+
*/
28+
private boolean dockerExistsOnThisSystem = false;
29+
30+
/**
31+
*
32+
*/
33+
@Before
34+
public void before() {
35+
// FIXME set the docker exists flag
36+
}
37+
38+
/**
39+
* Check that the Docker Client can get a reference to the
40+
* underlying docker daemon.
41+
*/
42+
@Test
43+
public void checkGetDockerClient() {
44+
45+
if (dockerExistsOnThisSystem) {
46+
System.out.println("DockerClientFactoryTest: Docker exists on this system - running test.");
47+
DockerClientFactory factory = new DockerClientFactory();
48+
DockerClient client = null;
49+
try {
50+
client = factory.getDockerClient();
51+
} catch (DockerCertificateException | IOException | InterruptedException e) {
52+
e.printStackTrace();
53+
fail();
54+
}
55+
System.out.println("DOCKER_HOST = " + client.getHost());
56+
assertNotNull(client);
57+
} else {
58+
System.out.println("DockerClientFactoryTest: Docker does not exist on this system - skipping test.");
59+
assertTrue(true);
60+
}
61+
}
62+
}

org.eclipse.ice.item/META-INF/MANIFEST.MF

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Bundle-SymbolicName: org.eclipse.ice.item;singleton:=true
55
Bundle-Version: 2.1.8.20160208
66
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
77
Import-Package: com.google.common.collect;version="10.0.1",
8+
com.google.common.net;version="15.0.0",
89
com.jcraft.jsch;version="0.1.51",
910
com.spotify.docker.client,
1011
com.spotify.docker.client.messages,

org.eclipse.ice.item/build.properties

+2-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ bin.includes = META-INF/,\
77
OSGi-INF/MOOSEIO.xml,\
88
OSGi-INF/jobLauncherRemote.xml,\
99
OSGi-INF/mooseModelRemote.xml,\
10-
deps/snakeyaml/com.springsource.snakeyaml-1.6.0.jar
10+
deps/snakeyaml/com.springsource.snakeyaml-1.6.0.jar,\
11+
resources/
1112
output.. = bin/
1213
src.includes = pom.xml
1314
source.. = src/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#!/usr/bin/env sh
2+
$SHELL -i -l -c "env | grep DOCKER"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
@echo off
2+
SET DOCKER

org.eclipse.ice.item/src/org/eclipse/ice/item/action/CreateDockerContainerAction.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
import org.eclipse.core.runtime.NullProgressMonitor;
1818
import org.eclipse.ice.datastructures.form.FormStatus;
19+
import org.eclipse.ice.item.jobLauncher.DockerClientFactory;
1920
import org.eclipse.remote.core.IRemoteConnection;
2021
import org.eclipse.remote.core.IRemoteConnectionHostService;
2122
import org.eclipse.remote.core.IRemoteConnectionType;
@@ -75,8 +76,8 @@ public FormStatus execute(Dictionary<String, String> dictionary) {
7576
status = FormStatus.Processing;
7677

7778
try {
78-
dockerClient = DefaultDockerClient.fromEnv().build();
79-
} catch (DockerCertificateException e1) {
79+
dockerClient = new DockerClientFactory().getDockerClient();
80+
} catch (DockerCertificateException | IOException | InterruptedException e1) {
8081
actionError("Error in getting a reference to Docker or listing available Images.", e1);
8182
return status;
8283
}
@@ -117,8 +118,7 @@ public FormStatus execute(Dictionary<String, String> dictionary) {
117118
port = result.split(":")[1];
118119

119120
// Get the hostname for the Docker container
120-
String dockerHost = System.getenv("DOCKER_HOST");
121-
String hostName = dockerHost.split(":")[1].replace("/", "");
121+
String hostName = dockerClient.getHost();
122122
dictionary.put("hostname", hostName);
123123
dictionary.put("remoteConnectionName", "Docker Host - " + hostName + ":" + port);
124124
dictionary.put("containerId", containerId);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
package org.eclipse.ice.item.jobLauncher;
2+
3+
import java.io.BufferedReader;
4+
import java.io.File;
5+
import java.io.FileOutputStream;
6+
import java.io.IOException;
7+
import java.io.InputStream;
8+
import java.io.InputStreamReader;
9+
import java.nio.file.Path;
10+
import java.nio.file.Paths;
11+
import java.util.Properties;
12+
13+
import org.eclipse.core.runtime.Platform;
14+
import org.osgi.framework.Bundle;
15+
import org.slf4j.Logger;
16+
import org.slf4j.LoggerFactory;
17+
18+
import com.google.common.net.HostAndPort;
19+
import com.spotify.docker.client.DefaultDockerClient;
20+
import com.spotify.docker.client.DefaultDockerClient.Builder;
21+
import com.spotify.docker.client.DockerCertificateException;
22+
import com.spotify.docker.client.DockerCertificates;
23+
import com.spotify.docker.client.DockerClient;
24+
25+
/**
26+
* This class provides a factory method for creating
27+
* the DefaultDockerClient in a way that is OS independent.
28+
*
29+
* @author Alex McCAskey
30+
*
31+
*/
32+
public class DockerClientFactory {
33+
34+
/**
35+
* Logger for handling event messages and other information.
36+
*/
37+
protected static final Logger logger = LoggerFactory.getLogger(DockerClientFactory.class);
38+
39+
/**
40+
* This method returns the DockerClient dependent on the current OS.
41+
*
42+
* @return
43+
* @throws DockerCertificateException
44+
* @throws IOException
45+
* @throws InterruptedException
46+
*/
47+
public DockerClient getDockerClient() throws DockerCertificateException, IOException, InterruptedException {
48+
DockerClient client = null;
49+
50+
// If this is not Linux, then we have to find DOCKER_HOST
51+
if (!Platform.getOS().equals(Platform.OS_LINUX)) {
52+
53+
// See if we can get the DOCKER_HOST environment variaable
54+
String dockerHost = System.getenv("DOCKER_HOST");
55+
if (dockerHost == null) {
56+
57+
// If not, run a script to see if we can get it
58+
File script = getDockerConnectionScript();
59+
String[] scriptExec = null;
60+
if (Platform.getOS().equals(Platform.OS_MACOSX)) {
61+
scriptExec = new String[]{script.getAbsolutePath()};
62+
} else if (Platform.getOS().equals(Platform.OS_WIN32)) {
63+
scriptExec = new String[]{"cmd.exe", "/C", script.getAbsolutePath()};
64+
}
65+
66+
// Execute the script to get the DOCKER vars.
67+
Process process = new ProcessBuilder(scriptExec).start();
68+
process.waitFor();
69+
int exitValue = process.exitValue();
70+
if (exitValue == 0) {
71+
72+
// Read them into a Properties object
73+
InputStream processInputStream = process.getInputStream();
74+
Properties dockerSettings = new Properties();
75+
dockerSettings.load(processInputStream);
76+
77+
// Create the Builder object that wil build the DockerClient
78+
Builder builder = new Builder();
79+
80+
// Get the DOCKER_HOST and CERT_PATH vars
81+
String endpoint = dockerSettings.getProperty("DOCKER_HOST");
82+
Path dockerCertPath = Paths.get(dockerSettings.getProperty("DOCKER_CERT_PATH"));
83+
84+
// Set up the certificates
85+
DockerCertificates certs = DockerCertificates.builder().dockerCertPath(dockerCertPath).build();
86+
87+
// Set the data need for the builder.
88+
final String stripped = endpoint.replaceAll(".*://", "");
89+
final HostAndPort hostAndPort = HostAndPort.fromString(stripped);
90+
final String hostText = hostAndPort.getHostText();
91+
final String scheme = certs != null ? "https" : "http";
92+
final int port = hostAndPort.getPortOrDefault(2375);
93+
final String address = hostText;
94+
builder.uri(scheme + "://" + address + ":" + port);
95+
if (certs != null) {
96+
builder.dockerCertificates(certs);
97+
}
98+
99+
// Build the Dockerclient!
100+
client = builder.build();
101+
102+
} else {
103+
// log what happened if the process did not end as expected
104+
// an exit value of 1 should indicate no connection found
105+
InputStream processErrorStream = process.getErrorStream();
106+
String errorMessage = streamToString(processErrorStream);
107+
logger.error("Error in getting DOCKER variables: " + errorMessage);
108+
}
109+
} else {
110+
client = DefaultDockerClient.fromEnv().build();
111+
}
112+
}
113+
114+
return client;
115+
}
116+
117+
/**
118+
* This method gets the script file for finding the Docker
119+
* environment variables.
120+
*
121+
* @return
122+
*/
123+
private File getDockerConnectionScript() {
124+
String scriptName = "";
125+
if (Platform.getOS().equals(Platform.OS_MACOSX)) {
126+
scriptName = "script-macosx.sh";
127+
} else if (Platform.getOS().equals(Platform.OS_WIN32)) {
128+
scriptName = "script.bat";
129+
}
130+
131+
Bundle bundle = Platform.getBundle("org.eclipse.ice.item");
132+
final File script = bundle
133+
.getDataFile(scriptName);
134+
135+
// if the script file does not exist or is outdated.
136+
if (script != null
137+
&& (!script.exists() || script.lastModified() < bundle.getLastModified())) {
138+
try (final FileOutputStream output = new FileOutputStream(
139+
script);
140+
final InputStream is = DockerClientFactory.class
141+
.getResourceAsStream(
142+
"/resources/" + scriptName)) {
143+
byte[] buff = new byte[1024];
144+
int n;
145+
while ((n = is.read(buff)) > 0) {
146+
output.write(buff, 0, n);
147+
}
148+
script.setExecutable(true);
149+
} catch (IOException e) {
150+
logger.error("Error in getting input file.", e);
151+
}
152+
}
153+
return script;
154+
}
155+
156+
/**
157+
* Private utility for getting string from InputStream.
158+
* @param stream
159+
* @return
160+
*/
161+
private String streamToString(InputStream stream) {
162+
BufferedReader buff = new BufferedReader(new InputStreamReader(stream));
163+
StringBuffer res = new StringBuffer();
164+
String line = ""; //$NON-NLS-1$
165+
try {
166+
while ((line = buff.readLine()) != null) {
167+
res.append(System.getProperty("line.separator"));
168+
res.append(line);
169+
}
170+
buff.close();
171+
} catch (IOException e) {
172+
}
173+
return res.length() > 0 ? res.substring(1) : "";
174+
}
175+
176+
}

org.eclipse.ice.item/src/org/eclipse/ice/item/jobLauncher/JobLauncherForm.java

+19-10
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
*******************************************************************************/
1313
package org.eclipse.ice.item.jobLauncher;
1414

15+
import java.io.IOException;
1516
import java.util.ArrayList;
1617
import java.util.Arrays;
1718
import java.util.List;
@@ -121,7 +122,7 @@ public class JobLauncherForm extends Form {
121122
*/
122123
private static final String TBBEntryName = "Number of TBB Threads";
123124

124-
private boolean dockerAvailable;
125+
private DockerClientFactory clientFactory;
125126

126127
/**
127128
* <p>
@@ -169,16 +170,24 @@ public void update(IUpdateable component) {
169170
// Set up the allowed values
170171
DockerClient dockerClient;
171172
try {
172-
dockerClient = DefaultDockerClient.fromEnv().build();
173-
allowedValues = new ArrayList<String>();
174-
for (Image i : dockerClient.listImages()) {
175-
allowedValues.add(i.repoTags().get(0));
176-
}
177-
if (allowedValues.isEmpty()) {
178-
allowedValues.add("No Images Found.");
173+
dockerClient = new DockerClientFactory().getDockerClient();
174+
if (dockerClient != null) {
175+
allowedValues = new ArrayList<String>();
176+
for (Image i : dockerClient.listImages()) {
177+
allowedValues.add(i.repoTags().get(0));
178+
}
179+
if (allowedValues.isEmpty()) {
180+
allowedValues.add("No Images Found.");
181+
}
182+
setValue(allowedValues.get(0));
183+
} else {
184+
logger.error("Error in getting a reference to Docker or listing available Images.");
185+
allowedValues = new ArrayList<String>();
186+
allowedValues.add("Error connecting to Docker.");
187+
setValue(allowedValues.get(0));
188+
return;
179189
}
180-
setValue(allowedValues.get(0));
181-
} catch (DockerCertificateException | DockerException | InterruptedException e1) {
190+
} catch (DockerCertificateException | DockerException | InterruptedException | IOException e1) {
182191
e1.printStackTrace();
183192
logger.error("Error in getting a reference to Docker or listing available Images.", e1);
184193
allowedValues = new ArrayList<String>();

0 commit comments

Comments
 (0)