122 return true; 123 } 124 125 126 /** 127 * Build a docker image that contains JDK under test. 128 * The jdk will be placed under the "/jdk/" folder inside the docker file system. 129 * 130 * @param imageName name of the image to be created, including version tag 131 * @param dockerfile name of the dockerfile residing in the test source; 132 * we check for a platform specific dockerfile as well 133 * and use this one in case it exists 134 * @param buildDirName name of the docker build/staging directory, which will 135 * be created in the jtreg's scratch folder 136 * @throws Exception 137 */ 138 public static void 139 buildJdkDockerImage(String imageName, String dockerfile, String buildDirName) 140 throws Exception { 141 142 Path buildDir = Paths.get(".", buildDirName); 143 if (Files.exists(buildDir)) { 144 throw new RuntimeException("The docker build directory already exists: " + buildDir); 145 } 146 147 Path jdkSrcDir = Paths.get(JDK_UNDER_TEST); 148 Path jdkDstDir = buildDir.resolve("jdk"); 149 150 Files.createDirectories(jdkDstDir); 151 152 // Copy JDK-under-test tree to the docker build directory. 153 // This step is required for building a docker image. 154 Files.walkFileTree(jdkSrcDir, new CopyFileVisitor(jdkSrcDir, jdkDstDir)); 155 buildDockerImage(imageName, Paths.get(Utils.TEST_SRC, dockerfile), buildDir); 156 } 157 158 159 /** 160 * Build a docker image based on given docker file and docker build directory. 161 * 162 * @param imageName name of the image to be created, including version tag 163 * @param dockerfile path to the Dockerfile to be used for building the docker 164 * image. The specified dockerfile will be copied to the docker build 165 * directory as 'Dockerfile' 166 * @param buildDir build directory; it should already contain all the content 167 * needed to build the docker image. 168 * @throws Exception 169 */ 170 public static void 171 buildDockerImage(String imageName, Path dockerfile, Path buildDir) throws Exception { 172 173 generateDockerFile(buildDir.resolve("Dockerfile"), 174 DockerfileConfig.getBaseImageName(), 175 DockerfileConfig.getBaseImageVersion()); 176 try { 177 // Build the docker 178 execute(Container.ENGINE_COMMAND, "build", "--no-cache", "--tag", imageName, buildDir.toString()) 179 .shouldHaveExitValue(0); 180 } catch (Exception e) { 181 // If docker image building fails there is a good chance it happens due to environment and/or 182 // configuration other than product failure. Throw jtreg skipped exception in such case 183 // instead of failing the test. 184 throw new SkippedException("Building docker image failed. Details: \n" + e.getMessage()); 185 } 186 } 187 188 189 /** 190 * Build the docker command to run java inside a container 191 * 192 * @param DockerRunOptions options for running docker 193 * 194 * @return command 195 * @throws Exception 196 */ 197 public static List<String> buildJavaCommand(DockerRunOptions opts) throws Exception { 198 List<String> cmd = new ArrayList<>(); 199 200 cmd.add(Container.ENGINE_COMMAND); 201 cmd.add("run"); 202 if (opts.tty) 203 cmd.add("--tty=true"); 204 if (opts.removeContainerAfterUse) 205 cmd.add("--rm"); 270 271 long started = System.currentTimeMillis(); 272 Process p = pb.start(); 273 long pid = p.pid(); 274 OutputAnalyzer output = new OutputAnalyzer(p); 275 276 String stdoutLogFile = String.format("docker-stdout-%d.log", pid); 277 System.out.println("[ELAPSED: " + (System.currentTimeMillis() - started) + " ms]"); 278 System.out.println("[STDERR]\n" + output.getStderr()); 279 System.out.println("[STDOUT]\n" + 280 trimLines(output.getStdout(),MAX_LINES_TO_COPY_FOR_CHILD_STDOUT)); 281 System.out.printf("Child process STDOUT is trimmed to %d lines \n", 282 MAX_LINES_TO_COPY_FOR_CHILD_STDOUT); 283 writeOutputToFile(output.getStdout(), stdoutLogFile); 284 System.out.println("Full child process STDOUT was saved to " + stdoutLogFile); 285 286 return output; 287 } 288 289 290 private static void writeOutputToFile(String output, String fileName) throws Exception { 291 try (FileWriter fw = new FileWriter(fileName)) { 292 fw.write(output, 0, output.length()); 293 } 294 } 295 296 297 private static String trimLines(String buffer, int nrOfLines) { 298 List<String> l = Arrays.asList(buffer.split("\\R")); 299 if (l.size() < nrOfLines) { 300 return buffer; 301 } 302 303 return String.join("\n", l.subList(0, nrOfLines)); 304 } 305 306 307 private static void generateDockerFile(Path dockerfile, String baseImage, 308 String baseImageVersion) throws Exception { 309 String template = 310 "FROM %s:%s\n" + 311 "COPY /jdk /jdk\n" + 312 "ENV JAVA_HOME=/jdk\n" + 313 "CMD [\"/bin/bash\"]\n"; 314 String dockerFileStr = String.format(template, baseImage, baseImageVersion); 315 Files.writeString(dockerfile, dockerFileStr); 316 } 317 318 319 private static class CopyFileVisitor extends SimpleFileVisitor<Path> { 320 private final Path src; 321 private final Path dst; 322 323 public CopyFileVisitor(Path src, Path dst) { 324 this.src = src; 325 this.dst = dst; 326 } 327 328 329 @Override 330 public FileVisitResult preVisitDirectory(Path file, 331 BasicFileAttributes attrs) throws IOException { 332 Path dstDir = dst.resolve(src.relativize(file)); 333 if (!dstDir.toFile().exists()) { 334 Files.createDirectories(dstDir); 335 } 336 return FileVisitResult.CONTINUE; 337 } 338 | 122 return true; 123 } 124 125 126 /** 127 * Build a docker image that contains JDK under test. 128 * The jdk will be placed under the "/jdk/" folder inside the docker file system. 129 * 130 * @param imageName name of the image to be created, including version tag 131 * @param dockerfile name of the dockerfile residing in the test source; 132 * we check for a platform specific dockerfile as well 133 * and use this one in case it exists 134 * @param buildDirName name of the docker build/staging directory, which will 135 * be created in the jtreg's scratch folder 136 * @throws Exception 137 */ 138 public static void 139 buildJdkDockerImage(String imageName, String dockerfile, String buildDirName) 140 throws Exception { 141 142 buildJdkDockerImage(imageName, dockerfile, buildDirName, ""); 143 } 144 145 /** 146 * Build a docker image that contains JDK under test. 147 * The jdk will be placed under the "/jdk/" folder inside the docker file system. 148 * 149 * @param imageName name of the image to be created, including version tag 150 * @param dockerfile name of the dockerfile residing in the test source; 151 * we check for a platform specific dockerfile as well 152 * and use this one in case it exists 153 * @param buildDirName name of the docker build/staging directory, which will 154 * be created in the jtreg's scratch folder 155 * @param additionalDockerFileContent 156 * additional docker file content to be appended to the 157 * template 158 * @throws Exception 159 */ 160 public static void 161 buildJdkDockerImage(String imageName, String dockerfile, 162 String buildDirName, String additionalDockerFileContent) 163 throws Exception { 164 165 Path buildDir = Paths.get(".", buildDirName); 166 if (Files.exists(buildDir)) { 167 throw new RuntimeException("The docker build directory already exists: " + buildDir); 168 } 169 170 Path jdkSrcDir = Paths.get(JDK_UNDER_TEST); 171 Path jdkDstDir = buildDir.resolve("jdk"); 172 173 Files.createDirectories(jdkDstDir); 174 175 // Copy JDK-under-test tree to the docker build directory. 176 // This step is required for building a docker image. 177 Files.walkFileTree(jdkSrcDir, new CopyFileVisitor(jdkSrcDir, jdkDstDir)); 178 buildDockerImage(imageName, Paths.get(Utils.TEST_SRC, dockerfile), 179 buildDir, additionalDockerFileContent); 180 } 181 182 183 /** 184 * Build a docker image based on given docker file and docker build directory. 185 * 186 * @param imageName name of the image to be created, including version tag 187 * @param dockerfile path to the Dockerfile to be used for building the docker 188 * image. The specified dockerfile will be copied to the docker build 189 * directory as 'Dockerfile' 190 * @param buildDir build directory; it should already contain all the content 191 * needed to build the docker image. 192 * @param additionalDockerfileContent additional docker file content, to be added 193 * after the basic template 194 * @throws Exception 195 */ 196 public static void 197 buildDockerImage(String imageName, Path dockerfile, 198 Path buildDir, String additionalDockerfileContent) throws Exception { 199 200 generateDockerFile(buildDir.resolve("Dockerfile"), 201 DockerfileConfig.getBaseImageName(), 202 DockerfileConfig.getBaseImageVersion(), 203 additionalDockerfileContent); 204 try { 205 // Build the docker 206 execute(Container.ENGINE_COMMAND, "build", "--no-cache", "--tag", imageName, buildDir.toString()) 207 .shouldHaveExitValue(0) 208 .shouldContain("Successfully built"); 209 } catch (Exception e) { 210 // If docker image building fails there is a good chance it happens due to environment and/or 211 // configuration other than product failure. Throw jtreg skipped exception in such case 212 // instead of failing the test. 213 throw new SkippedException("Building docker image failed. Details: \n" + e.getMessage()); 214 } 215 216 } 217 218 /** 219 * Build a docker image based on given docker file and docker build directory. 220 * 221 * @param imageName name of the image to be created, including version tag 222 * @param dockerfile path to the Dockerfile to be used for building the docker 223 * image. The specified dockerfile will be copied to the docker build 224 * directory as 'Dockerfile' 225 * @param buildDir build directory; it should already contain all the content 226 * needed to build the docker image. 227 * @throws Exception 228 */ 229 public static void 230 buildDockerImage(String imageName, Path dockerfile, Path buildDir) throws Exception { 231 buildDockerImage(imageName, dockerfile, buildDir, ""); 232 } 233 234 235 /** 236 * Build the docker command to run java inside a container 237 * 238 * @param DockerRunOptions options for running docker 239 * 240 * @return command 241 * @throws Exception 242 */ 243 public static List<String> buildJavaCommand(DockerRunOptions opts) throws Exception { 244 List<String> cmd = new ArrayList<>(); 245 246 cmd.add(Container.ENGINE_COMMAND); 247 cmd.add("run"); 248 if (opts.tty) 249 cmd.add("--tty=true"); 250 if (opts.removeContainerAfterUse) 251 cmd.add("--rm"); 316 317 long started = System.currentTimeMillis(); 318 Process p = pb.start(); 319 long pid = p.pid(); 320 OutputAnalyzer output = new OutputAnalyzer(p); 321 322 String stdoutLogFile = String.format("docker-stdout-%d.log", pid); 323 System.out.println("[ELAPSED: " + (System.currentTimeMillis() - started) + " ms]"); 324 System.out.println("[STDERR]\n" + output.getStderr()); 325 System.out.println("[STDOUT]\n" + 326 trimLines(output.getStdout(),MAX_LINES_TO_COPY_FOR_CHILD_STDOUT)); 327 System.out.printf("Child process STDOUT is trimmed to %d lines \n", 328 MAX_LINES_TO_COPY_FOR_CHILD_STDOUT); 329 writeOutputToFile(output.getStdout(), stdoutLogFile); 330 System.out.println("Full child process STDOUT was saved to " + stdoutLogFile); 331 332 return output; 333 } 334 335 336 /** 337 * Check if a container is running 338 * 339 * @param name container name 340 * @return True if container is running 341 * @throws Exception 342 */ 343 public static boolean isContainerRunning(String name) throws Exception { 344 OutputAnalyzer out = 345 DockerTestUtils.execute(Container.ENGINE_COMMAND, 346 "ps", "--no-trunc", 347 "--filter", "name=" + name); 348 return out.getStdout().contains(name); 349 } 350 351 352 /** 353 * Wait for container to start 354 * 355 * @param name container name 356 * @param initialDelay initial delay (milliseconds) before the first check 357 * @param checkDelay delay between checks (milliseconds) 358 * @param count how many times to check before giving up 359 * @throws Exception will throw an exception if a specified container did not start 360 */ 361 public static void waitForContainerToStart(String name, int initialDelay, 362 int checkDelay, int count) throws Exception { 363 boolean started = false; 364 365 try { Thread.sleep(initialDelay); } catch (InterruptedException e) {} 366 367 for(int i=0; i < count; i++) { 368 try { Thread.sleep(checkDelay); } catch (InterruptedException e) {} 369 if (isContainerRunning(name)) { 370 started = true; 371 break; 372 } 373 System.out.println("The main container has not started yet, count = " + i); 374 } 375 if (!started) { 376 throw new RuntimeException("Main container did not start"); 377 } 378 } 379 380 381 private static void writeOutputToFile(String output, String fileName) throws Exception { 382 try (FileWriter fw = new FileWriter(fileName)) { 383 fw.write(output, 0, output.length()); 384 } 385 } 386 387 388 private static String trimLines(String buffer, int nrOfLines) { 389 List<String> l = Arrays.asList(buffer.split("\\R")); 390 if (l.size() < nrOfLines) { 391 return buffer; 392 } 393 394 return String.join("\n", l.subList(0, nrOfLines)); 395 } 396 397 398 private static void generateDockerFile(Path dockerfile, String baseImage, 399 String baseImageVersion, 400 String additionalDockerfileContent) throws Exception { 401 String template = 402 "FROM %s:%s\n" + 403 "COPY /jdk /jdk\n" + 404 "ENV JAVA_HOME=/jdk\n" + 405 "CMD [\"/bin/bash\"]\n" + 406 additionalDockerfileContent; 407 408 String dockerFileStr = String.format(template, baseImage, baseImageVersion); 409 Files.writeString(dockerfile, dockerFileStr); 410 } 411 412 private static class CopyFileVisitor extends SimpleFileVisitor<Path> { 413 private final Path src; 414 private final Path dst; 415 416 public CopyFileVisitor(Path src, Path dst) { 417 this.src = src; 418 this.dst = dst; 419 } 420 421 422 @Override 423 public FileVisitResult preVisitDirectory(Path file, 424 BasicFileAttributes attrs) throws IOException { 425 Path dstDir = dst.resolve(src.relativize(file)); 426 if (!dstDir.toFile().exists()) { 427 Files.createDirectories(dstDir); 428 } 429 return FileVisitResult.CONTINUE; 430 } 431 |