20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24 package jdk.test.lib.containers.docker;
25
26 import java.io.File;
27 import java.io.FileWriter;
28 import java.io.IOException;
29 import java.nio.file.Files;
30 import java.nio.file.FileVisitResult;
31 import java.nio.file.Path;
32 import java.nio.file.Paths;
33 import java.nio.file.SimpleFileVisitor;
34 import java.nio.file.StandardCopyOption;
35 import java.nio.file.attribute.BasicFileAttributes;
36 import java.util.Arrays;
37 import java.util.ArrayList;
38 import java.util.Collections;
39 import java.util.List;
40 import jdk.test.lib.Utils;
41 import jdk.test.lib.process.OutputAnalyzer;
42 import jdk.test.lib.process.ProcessTools;
43 import jtreg.SkippedException;
44
45
46 public class DockerTestUtils {
47 private static final String FS = File.separator;
48 private static boolean isDockerEngineAvailable = false;
49 private static boolean wasDockerEngineChecked = false;
50
51 // Specifies how many lines to copy from child STDOUT to main test output.
52 // Having too many lines in the main test output will result
53 // in JT harness trimming the output, and can lead to loss of useful
54 // diagnostic information.
55 private static final int MAX_LINES_TO_COPY_FOR_CHILD_STDOUT = 100;
56
57 // Use this property to specify docker location on your system.
58 // E.g.: "/usr/local/bin/docker".
59 private static final String DOCKER_COMMAND =
60 System.getProperty("jdk.test.docker.command", "docker");
61
62 // Set this property to true to retain image after test. By default
63 // images are removed after test execution completes.
64 // Retaining the image can be useful for diagnostics and image inspection.
65 // E.g.: start image interactively: docker run -it <IMAGE_NAME>.
66 public static final boolean RETAIN_IMAGE_AFTER_TEST =
67 Boolean.getBoolean("jdk.test.docker.retain.image");
68
69 // Path to a JDK under test.
70 // This may be useful when developing tests on non-Linux platforms.
71 public static final String JDK_UNDER_TEST =
72 System.getProperty("jdk.test.docker.jdk", Utils.TEST_JDK);
73
74
75 /**
76 * Optimized check of whether the docker engine is available in a given
77 * environment. Checks only once, then remembers the result in a singleton.
78 *
79 * @return true if docker engine is available
80 * @throws Exception
81 */
99 public static boolean canTestDocker() throws Exception {
100 if (isDockerEngineAvailable()) {
101 return true;
102 } else {
103 throw new SkippedException("Docker engine is not available on this system");
104 }
105 }
106
107
108 /**
109 * Simple check - is docker engine available, accessible and usable.
110 * Run basic docker command: 'docker ps' - list docker instances.
111 * If docker engine is available and accesible then true is returned
112 * and we can proceed with testing docker.
113 *
114 * @return true if docker engine is available and usable
115 * @throws Exception
116 */
117 private static boolean isDockerEngineAvailableCheck() throws Exception {
118 try {
119 execute(DOCKER_COMMAND, "ps")
120 .shouldHaveExitValue(0)
121 .shouldContain("CONTAINER")
122 .shouldContain("IMAGE");
123 } catch (Exception e) {
124 return false;
125 }
126 return true;
127 }
128
129
130 /**
131 * Build a docker image that contains JDK under test.
132 * The jdk will be placed under the "/jdk/" folder inside the docker file system.
133 *
134 * @param imageName name of the image to be created, including version tag
135 * @param dockerfile name of the dockerfile residing in the test source;
136 * we check for a platform specific dockerfile as well
137 * and use this one in case it exists
138 * @param buildDirName name of the docker build/staging directory, which will
139 * be created in the jtreg's scratch folder
162
163 /**
164 * Build a docker image based on given docker file and docker build directory.
165 *
166 * @param imageName name of the image to be created, including version tag
167 * @param dockerfile path to the Dockerfile to be used for building the docker
168 * image. The specified dockerfile will be copied to the docker build
169 * directory as 'Dockerfile'
170 * @param buildDir build directory; it should already contain all the content
171 * needed to build the docker image.
172 * @throws Exception
173 */
174 public static void
175 buildDockerImage(String imageName, Path dockerfile, Path buildDir) throws Exception {
176
177 generateDockerFile(buildDir.resolve("Dockerfile"),
178 DockerfileConfig.getBaseImageName(),
179 DockerfileConfig.getBaseImageVersion());
180 try {
181 // Build the docker
182 execute(DOCKER_COMMAND, "build", "--no-cache", "--tag", imageName, buildDir.toString())
183 .shouldHaveExitValue(0)
184 .shouldContain("Successfully built");
185 } catch (Exception e) {
186 // If docker image building fails there is a good chance it happens due to environment and/or
187 // configuration other than product failure. Throw jtreg skipped exception in such case
188 // instead of failing the test.
189 throw new SkippedException("Building docker image failed. Details: \n" + e.getMessage());
190 }
191 }
192
193
194 /**
195 * Build the docker command to run java inside a container
196 *
197 * @param DockerRunOptions optins for running docker
198 *
199 * @return command
200 * @throws Exception
201 */
202 public static List<String> buildJavaCommand(DockerRunOptions opts) throws Exception {
203 List<String> cmd = new ArrayList<>();
204
205 cmd.add(DOCKER_COMMAND);
206 cmd.add("run");
207 if (opts.tty)
208 cmd.add("--tty=true");
209 if (opts.removeContainerAfterUse)
210 cmd.add("--rm");
211
212 cmd.addAll(opts.dockerOpts);
213 cmd.add(opts.imageNameAndTag);
214 cmd.add(opts.command);
215
216 cmd.addAll(opts.javaOpts);
217 if (opts.appendTestJavaOptions) {
218 Collections.addAll(cmd, Utils.getTestJavaOpts());
219 }
220
221 cmd.add(opts.classToRun);
222 cmd.addAll(opts.classParams);
223
224 return cmd;
225 }
227 /**
228 * Run Java inside the docker image with specified parameters and options.
229 *
230 * @param DockerRunOptions optins for running docker
231 *
232 * @return output of the run command
233 * @throws Exception
234 */
235 public static OutputAnalyzer dockerRunJava(DockerRunOptions opts) throws Exception {
236 return execute(buildJavaCommand(opts));
237 }
238
239
240 /**
241 * Remove docker image
242 *
243 * @param DockerRunOptions optins for running docker
244 * @throws Exception
245 */
246 public static void removeDockerImage(String imageNameAndTag) throws Exception {
247 execute(DOCKER_COMMAND, "rmi", "--force", imageNameAndTag);
248 }
249
250
251
252 /**
253 * Convenience method - express command as sequence of strings
254 *
255 * @param command to execute
256 * @return The output from the process
257 * @throws Exception
258 */
259 public static OutputAnalyzer execute(List<String> command) throws Exception {
260 return execute(command.toArray(new String[command.size()]));
261 }
262
263
264 /**
265 * Execute a specified command in a process, report diagnostic info.
266 *
267 * @param command to be executed
|
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24 package jdk.test.lib.containers.docker;
25
26 import java.io.File;
27 import java.io.FileWriter;
28 import java.io.IOException;
29 import java.nio.file.Files;
30 import java.nio.file.FileVisitResult;
31 import java.nio.file.Path;
32 import java.nio.file.Paths;
33 import java.nio.file.SimpleFileVisitor;
34 import java.nio.file.StandardCopyOption;
35 import java.nio.file.attribute.BasicFileAttributes;
36 import java.util.Arrays;
37 import java.util.ArrayList;
38 import java.util.Collections;
39 import java.util.List;
40 import java.util.Map;
41 import jdk.test.lib.Platform;
42 import jdk.test.lib.Utils;
43 import jdk.test.lib.process.OutputAnalyzer;
44 import jdk.test.lib.process.ProcessTools;
45 import jtreg.SkippedException;
46
47
48 public class DockerTestUtils {
49 private static final String FS = File.separator;
50 private static boolean isDockerEngineAvailable = false;
51 private static boolean wasDockerEngineChecked = false;
52
53 // Specifies how many lines to copy from child STDOUT to main test output.
54 // Having too many lines in the main test output will result
55 // in JT harness trimming the output, and can lead to loss of useful
56 // diagnostic information.
57 private static final int MAX_LINES_TO_COPY_FOR_CHILD_STDOUT = 100;
58
59 // Set this property to true to retain image after test. By default
60 // images are removed after test execution completes.
61 // Retaining the image can be useful for diagnostics and image inspection.
62 // E.g.: start image interactively: docker run -it <IMAGE_NAME>.
63 public static final boolean RETAIN_IMAGE_AFTER_TEST =
64 Boolean.getBoolean("jdk.test.docker.retain.image");
65
66 // Path to a JDK under test.
67 // This may be useful when developing tests on non-Linux platforms.
68 public static final String JDK_UNDER_TEST =
69 System.getProperty("jdk.test.docker.jdk", Utils.TEST_JDK);
70
71
72 /**
73 * Optimized check of whether the docker engine is available in a given
74 * environment. Checks only once, then remembers the result in a singleton.
75 *
76 * @return true if docker engine is available
77 * @throws Exception
78 */
96 public static boolean canTestDocker() throws Exception {
97 if (isDockerEngineAvailable()) {
98 return true;
99 } else {
100 throw new SkippedException("Docker engine is not available on this system");
101 }
102 }
103
104
105 /**
106 * Simple check - is docker engine available, accessible and usable.
107 * Run basic docker command: 'docker ps' - list docker instances.
108 * If docker engine is available and accesible then true is returned
109 * and we can proceed with testing docker.
110 *
111 * @return true if docker engine is available and usable
112 * @throws Exception
113 */
114 private static boolean isDockerEngineAvailableCheck() throws Exception {
115 try {
116 execute(Platform.DOCKER_COMMAND, "ps")
117 .shouldHaveExitValue(0)
118 .shouldContain("CONTAINER")
119 .shouldContain("IMAGE");
120 } catch (Exception e) {
121 return false;
122 }
123 return true;
124 }
125
126
127 /**
128 * Build a docker image that contains JDK under test.
129 * The jdk will be placed under the "/jdk/" folder inside the docker file system.
130 *
131 * @param imageName name of the image to be created, including version tag
132 * @param dockerfile name of the dockerfile residing in the test source;
133 * we check for a platform specific dockerfile as well
134 * and use this one in case it exists
135 * @param buildDirName name of the docker build/staging directory, which will
136 * be created in the jtreg's scratch folder
159
160 /**
161 * Build a docker image based on given docker file and docker build directory.
162 *
163 * @param imageName name of the image to be created, including version tag
164 * @param dockerfile path to the Dockerfile to be used for building the docker
165 * image. The specified dockerfile will be copied to the docker build
166 * directory as 'Dockerfile'
167 * @param buildDir build directory; it should already contain all the content
168 * needed to build the docker image.
169 * @throws Exception
170 */
171 public static void
172 buildDockerImage(String imageName, Path dockerfile, Path buildDir) throws Exception {
173
174 generateDockerFile(buildDir.resolve("Dockerfile"),
175 DockerfileConfig.getBaseImageName(),
176 DockerfileConfig.getBaseImageVersion());
177 try {
178 // Build the docker
179 execute(Platform.DOCKER_COMMAND, "build", "--no-cache", "--tag", imageName, buildDir.toString())
180 .shouldHaveExitValue(0);
181 } catch (Exception e) {
182 // If docker image building fails there is a good chance it happens due to environment and/or
183 // configuration other than product failure. Throw jtreg skipped exception in such case
184 // instead of failing the test.
185 throw new SkippedException("Building docker image failed. Details: \n" + e.getMessage());
186 }
187 }
188
189
190 /**
191 * Build the docker command to run java inside a container
192 *
193 * @param DockerRunOptions optins for running docker
194 *
195 * @return command
196 * @throws Exception
197 */
198 public static List<String> buildJavaCommand(DockerRunOptions opts) throws Exception {
199 List<String> cmd = new ArrayList<>();
200
201 cmd.add(Platform.DOCKER_COMMAND);
202 cmd.add("run");
203 if (opts.tty)
204 cmd.add("--tty=true");
205 if (opts.removeContainerAfterUse)
206 cmd.add("--rm");
207
208 cmd.addAll(opts.dockerOpts);
209 cmd.add(opts.imageNameAndTag);
210 cmd.add(opts.command);
211
212 cmd.addAll(opts.javaOpts);
213 if (opts.appendTestJavaOptions) {
214 Collections.addAll(cmd, Utils.getTestJavaOpts());
215 }
216
217 cmd.add(opts.classToRun);
218 cmd.addAll(opts.classParams);
219
220 return cmd;
221 }
223 /**
224 * Run Java inside the docker image with specified parameters and options.
225 *
226 * @param DockerRunOptions optins for running docker
227 *
228 * @return output of the run command
229 * @throws Exception
230 */
231 public static OutputAnalyzer dockerRunJava(DockerRunOptions opts) throws Exception {
232 return execute(buildJavaCommand(opts));
233 }
234
235
236 /**
237 * Remove docker image
238 *
239 * @param DockerRunOptions optins for running docker
240 * @throws Exception
241 */
242 public static void removeDockerImage(String imageNameAndTag) throws Exception {
243 execute(Platform.DOCKER_COMMAND, "rmi", "--force", imageNameAndTag);
244 }
245
246
247
248 /**
249 * Convenience method - express command as sequence of strings
250 *
251 * @param command to execute
252 * @return The output from the process
253 * @throws Exception
254 */
255 public static OutputAnalyzer execute(List<String> command) throws Exception {
256 return execute(command.toArray(new String[command.size()]));
257 }
258
259
260 /**
261 * Execute a specified command in a process, report diagnostic info.
262 *
263 * @param command to be executed
|