1 /* 2 * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 25 /* 26 * @test 27 * @summary Test JCMD with containers. 28 * Specifically, start the test JVM inside a container, then use jcmd to find it and 29 * send a simple command to that JVM. 30 * @requires docker.support 31 * @library /test/lib 32 * @modules java.base/jdk.internal.misc 33 * java.management 34 * jdk.jartool/sun.tools.jar 35 * jdk.security.auth 36 * @build SimpleLoop 37 * @run driver TestJcmd 38 */ 39 import com.sun.security.auth.module.UnixSystem; 40 import jdk.test.lib.JDKToolFinder; 41 import jdk.test.lib.Utils; 42 import jdk.test.lib.containers.docker.Common; 43 import jdk.test.lib.containers.docker.DockerRunOptions; 44 import jdk.test.lib.containers.docker.DockerTestUtils; 45 import jdk.test.lib.process.OutputAnalyzer; 46 47 48 public class TestJcmd { 49 private static final String IMAGE_NAME = Common.imageName("jcmd"); 50 private static final int TIME_TO_RUN_CHILD_PROCESS = (int) (20 * Utils.TIMEOUT_FACTOR); // seconds 51 52 public static void main(String[] args) throws Exception { 53 if (!DockerTestUtils.canTestDocker()) { 54 return; 55 } 56 57 // In order for jcmd to work, the USER name and UID of the observer 58 // need to match the USERNAME/UID of the observed JVM process 59 String additionalDockerFileContent = 60 String.format("RUN useradd %s --uid %d \n", getCurrentUserName(), getCurrentUserId()) + 61 String.format("USER %s \n", getCurrentUserName()); 62 63 DockerTestUtils.buildJdkDockerImage(IMAGE_NAME, "Dockerfile-BasicTest", 64 "jdk-docker", additionalDockerFileContent); 65 66 String name = "java-simple-loop"; 67 try { 68 ProcessBuilder pb = containerCommand(name); 69 Process p = pb.start(); 70 71 DockerTestUtils.waitForContainerToStart(name, 2000, 500, 10); 72 73 // jcmd -l 74 OutputAnalyzer jcmdOut = testJcmdList(); 75 long pid = Common.findPidFromJcmdOutput(jcmdOut, "SimpleLoop"); 76 System.out.println("PID = " + pid); 77 78 // jcmd <pid> help 79 // This test case currently fails due to JDK-8228343 80 // testJcmdHelp(pid); 81 82 p.waitFor(); 83 logProcess("container", pb, new OutputAnalyzer(p)); 84 } finally { 85 DockerTestUtils.removeDockerImage(IMAGE_NAME); 86 } 87 } 88 89 private static String getCurrentUserName() { 90 String name = System.getProperty("user.name"); 91 System.out.println("getCurrentUserName(): returning " + name); 92 return name; 93 } 94 95 private static long getCurrentUserId() { 96 long uid = (new UnixSystem()).getUid(); 97 System.out.println("getCurrentUserId(): returning " + uid); 98 return uid; 99 } 100 101 // Run "jcmd -l" 102 private static OutputAnalyzer testJcmdList() throws Exception { 103 ProcessBuilder pb = new ProcessBuilder(JDKToolFinder.getJDKTool("jcmd"), "-l"); 104 OutputAnalyzer out = new OutputAnalyzer(pb.start()); 105 logProcess("testJcmdList", pb, out); 106 107 out.shouldHaveExitValue(0) 108 .shouldContain("SimpleLoop"); 109 110 return out; 111 } 112 113 // run "jcmd <pid> help" 114 private static void testJcmdHelp(long pid) throws Exception { 115 ProcessBuilder pb = new ProcessBuilder(JDKToolFinder.getJDKTool("jcmd"), "" + pid, "help"); 116 OutputAnalyzer out = new OutputAnalyzer(pb.start()); 117 logProcess("testJcmdHelp", pb, out); 118 119 out.shouldHaveExitValue(0) 120 .shouldContain("VM.version"); 121 } 122 123 private static void logProcess(String logToken, ProcessBuilder pb, OutputAnalyzer out) { 124 System.out.printf("%s: [COMMAND]:\n%s\n", logToken, Utils.getCommandLine(pb)); 125 System.out.printf("%s: [STDERR]:\n%s\n", logToken, out.getStderr()); 126 System.out.printf("%s: [STDOUT]:\n%s\n", logToken, out.getStdout()); 127 } 128 129 private static ProcessBuilder containerCommand(String name) throws Exception { 130 // start container with monitored JVM inside 131 DockerRunOptions opts = new DockerRunOptions(IMAGE_NAME, "/jdk/bin/java", "SimpleLoop") 132 .addDockerOpts("--volume", Utils.TEST_CLASSES + ":/test-classes/") 133 .addJavaOpts("-cp", "/test-classes/") 134 .addDockerOpts("--cap-add=SYS_PTRACE") 135 .addDockerOpts("--name", name) 136 .addDockerOpts("--sig-proxy=true") 137 .addJavaOpts("-XX:+UsePerfData") 138 .addClassOptions("" + TIME_TO_RUN_CHILD_PROCESS); 139 140 return new ProcessBuilder(DockerTestUtils.buildJavaCommand(opts)); 141 } 142 }