From c12c4dba5dc0d62f7e3ec24ce8c1821f8d2eb718 Mon Sep 17 00:00:00 2001 From: kohsuke Date: Sun, 20 Jan 2008 19:20:34 +0000 Subject: [PATCH] Added a probe for the running Maven process to obtain system properties, environment variables, thread dump, and the scripting console. git-svn-id: https://hudson.dev.java.net/svn/hudson/trunk/hudson/main@6778 71c3de6d-444a-0410-be80-ed276b4c234a --- .../hudson/maven/MavenModuleSetBuild.java | 4 + .../java/hudson/maven/MavenProbeAction.java | 92 ++++++++++++++++++ core/src/main/java/hudson/model/Computer.java | 45 +-------- core/src/main/java/hudson/model/Hudson.java | 18 +--- .../java/hudson/util/RemotingDiagnostics.java | 94 +++++++++++++++++++ .../maven/MavenProbeAction/_script.jelly | 8 ++ .../maven/MavenProbeAction/envVars.jelly | 9 ++ .../hudson/maven/MavenProbeAction/index.jelly | 11 +++ .../maven/MavenProbeAction/sidepanel.jelly | 11 +++ .../MavenProbeAction/systemProperties.jelly | 10 ++ .../maven/MavenProbeAction/threads.jelly | 12 +++ .../hudson/maven/Messages.properties | 4 +- .../hudson/model/Hudson/_script.jelly | 32 +------ .../resources/lib/hudson/scriptConsole.jelly | 35 +++++++ 14 files changed, 301 insertions(+), 84 deletions(-) create mode 100644 core/src/main/java/hudson/maven/MavenProbeAction.java create mode 100644 core/src/main/java/hudson/util/RemotingDiagnostics.java create mode 100644 core/src/main/resources/hudson/maven/MavenProbeAction/_script.jelly create mode 100644 core/src/main/resources/hudson/maven/MavenProbeAction/envVars.jelly create mode 100644 core/src/main/resources/hudson/maven/MavenProbeAction/index.jelly create mode 100644 core/src/main/resources/hudson/maven/MavenProbeAction/sidepanel.jelly create mode 100644 core/src/main/resources/hudson/maven/MavenProbeAction/systemProperties.jelly create mode 100644 core/src/main/resources/hudson/maven/MavenProbeAction/threads.jelly create mode 100644 core/src/main/resources/lib/hudson/scriptConsole.jelly diff --git a/core/src/main/java/hudson/maven/MavenModuleSetBuild.java b/core/src/main/java/hudson/maven/MavenModuleSetBuild.java index 8191f37ca9..c2837aa2a7 100644 --- a/core/src/main/java/hudson/maven/MavenModuleSetBuild.java +++ b/core/src/main/java/hudson/maven/MavenModuleSetBuild.java @@ -262,10 +262,14 @@ public final class MavenModuleSetBuild extends AbstractBuild + * This action is added to a build when it's started, and removed + * when it's completed. + * + * @author Kohsuke Kawaguchi + * @since 1.175 + */ +public final class MavenProbeAction implements Action { + private final transient Channel channel; + + public final AbstractProject owner; + + MavenProbeAction(AbstractProject owner, Channel channel) { + this.channel = channel; + this.owner = owner; + } + + public String getIconFileName() { + if(channel==null) return null; + return "computer.gif"; + } + + public String getDisplayName() { + return Messages.MavenProbeAction_DisplayName(); + } + + public String getUrlName() { + if(channel==null) return null; + return "probe"; + } + + /** + * Gets the system properties of the JVM on this computer. + * If this is the master, it returns the system property of the master computer. + */ + public Map getSystemProperties() throws IOException, InterruptedException { + return RemotingDiagnostics.getSystemProperties(channel); + } + + /** + * Gets the environment variables of the JVM on this computer. + * If this is the master, it returns the system property of the master computer. + */ + public Map getEnvVars() throws IOException, InterruptedException { + return EnvVars.getRemote(channel); + } + + /** + * Gets the thread dump of the slave JVM. + * @return + * key is the thread name, and the value is the pre-formatted dump. + */ + public Map getThreadDump() throws IOException, InterruptedException { + return RemotingDiagnostics.getThreadDump(channel); + } + + public void doScript( StaplerRequest req, StaplerResponse rsp ) throws IOException, ServletException { + // ability to run arbitrary script is dangerous, + // so tie it to the admin access + owner.checkPermission(Hudson.ADMINISTER); + + String text = req.getParameter("script"); + if(text!=null) { + try { + req.setAttribute("output", + RemotingDiagnostics.executeGroovy(text,channel)); + } catch (InterruptedException e) { + throw new ServletException(e); + } + } + + req.getView(this,"_script.jelly").forward(req,rsp); + } +} diff --git a/core/src/main/java/hudson/model/Computer.java b/core/src/main/java/hudson/model/Computer.java index 3b3fc93968..6f254be9d6 100644 --- a/core/src/main/java/hudson/model/Computer.java +++ b/core/src/main/java/hudson/model/Computer.java @@ -1,13 +1,12 @@ package hudson.model; import hudson.EnvVars; -import hudson.Functions; -import hudson.remoting.Callable; import hudson.remoting.Channel; import hudson.remoting.VirtualChannel; -import hudson.tasks.Publisher; import hudson.tasks.BuildWrapper; +import hudson.tasks.Publisher; import hudson.util.DaemonThreadFactory; +import hudson.util.RemotingDiagnostics; import hudson.util.RunList; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; @@ -15,13 +14,9 @@ import org.kohsuke.stapler.StaplerResponse; import javax.servlet.ServletException; import java.io.IOException; import java.io.PrintWriter; -import java.lang.management.ThreadInfo; import java.util.ArrayList; -import java.util.Collections; -import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.TreeMap; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -257,14 +252,7 @@ public abstract class Computer extends AbstractModelObject { * If this is the master, it returns the system property of the master computer. */ public Map getSystemProperties() throws IOException, InterruptedException { - return getChannel().call(new GetSystemProperties()); - } - - private static final class GetSystemProperties implements Callable,RuntimeException> { - public Map call() { - return new TreeMap(System.getProperties()); - } - private static final long serialVersionUID = 1L; + return RemotingDiagnostics.getSystemProperties(getChannel()); } /** @@ -281,34 +269,9 @@ public abstract class Computer extends AbstractModelObject { * key is the thread name, and the value is the pre-formatted dump. */ public Map getThreadDump() throws IOException, InterruptedException { - VirtualChannel channel = getChannel(); - if(channel==null) - return Collections.singletonMap("N/A","N/A"); - return channel.call(new GetThreadDump()); + return RemotingDiagnostics.getThreadDump(getChannel()); } - private static final class GetThreadDump implements Callable,RuntimeException> { - public Map call() { - Map r = new LinkedHashMap(); - try { - for (ThreadInfo ti : Functions.getThreadInfos()) - r.put(ti.getThreadName(),Functions.dumpThreadInfo(ti)); - } catch (LinkageError _) { - // not in JDK6. fall back to JDK5 - r.clear(); - for (Map.Entry t : Thread.getAllStackTraces().entrySet()) { - StringBuffer buf = new StringBuffer(); - for (StackTraceElement e : t.getValue()) - buf.append(e).append('\n'); - r.put(t.getKey().getName(),buf.toString()); - } - } - return r; - } - private static final long serialVersionUID = 1L; - } - - public static final ExecutorService threadPoolForRemoting = Executors.newCachedThreadPool(new DaemonThreadFactory()); // diff --git a/core/src/main/java/hudson/model/Hudson.java b/core/src/main/java/hudson/model/Hudson.java index d1f6406557..79d2dc2a15 100644 --- a/core/src/main/java/hudson/model/Hudson.java +++ b/core/src/main/java/hudson/model/Hudson.java @@ -61,6 +61,7 @@ import hudson.util.HudsonIsLoading; import hudson.util.MultipartFormDataParser; import hudson.util.TextFile; import hudson.util.XStream2; +import hudson.util.RemotingDiagnostics; import hudson.widgets.Widget; import net.sf.json.JSONObject; import org.acegisecurity.Authentication; @@ -69,7 +70,6 @@ import org.acegisecurity.GrantedAuthorityImpl; import org.acegisecurity.context.SecurityContextHolder; import org.acegisecurity.providers.anonymous.AnonymousAuthenticationToken; import org.acegisecurity.ui.AbstractProcessingFilter; -import org.acegisecurity.ui.rememberme.TokenBasedRememberMeServices; import static org.acegisecurity.ui.rememberme.TokenBasedRememberMeServices.ACEGI_SECURITY_HASHED_REMEMBER_ME_COOKIE_KEY; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.disk.DiskFileItemFactory; @@ -81,7 +81,6 @@ import org.kohsuke.stapler.StaplerProxy; import org.kohsuke.stapler.StaplerRequest; import org.kohsuke.stapler.StaplerResponse; import org.kohsuke.stapler.export.Exported; -import org.springframework.util.StringUtils; import javax.servlet.ServletContext; import javax.servlet.ServletException; @@ -1920,19 +1919,12 @@ public final class Hudson extends View implements ItemGroup, Node, String text = req.getParameter("script"); if(text!=null) { - GroovyShell shell = new GroovyShell(); - - StringWriter out = new StringWriter(); - PrintWriter pw = new PrintWriter(out); - shell.setVariable("out", pw); try { - Object output = shell.evaluate(text); - if(output!=null) - pw.println("Result: "+output); - } catch (Throwable t) { - t.printStackTrace(pw); + req.setAttribute("output", + RemotingDiagnostics.executeGroovy(text, MasterComputer.localChannel)); + } catch (InterruptedException e) { + throw new ServletException(e); } - req.setAttribute("output",out); } req.getView(this,"_script.jelly").forward(req,rsp); diff --git a/core/src/main/java/hudson/util/RemotingDiagnostics.java b/core/src/main/java/hudson/util/RemotingDiagnostics.java new file mode 100644 index 0000000000..023b6bbed2 --- /dev/null +++ b/core/src/main/java/hudson/util/RemotingDiagnostics.java @@ -0,0 +1,94 @@ +package hudson.util; + +import groovy.lang.GroovyShell; +import hudson.Functions; +import hudson.remoting.Callable; +import hudson.remoting.VirtualChannel; + +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.lang.management.ThreadInfo; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.TreeMap; + +/** + * Various remoting operations related to diagnostics. + * + * @author Kohsuke Kawaguchi + * @since 1.175 + */ +public final class RemotingDiagnostics { + public static Map getSystemProperties(VirtualChannel channel) throws IOException, InterruptedException { + if(channel==null) + return Collections.singletonMap("N/A","N/A"); + return channel.call(new GetSystemProperties()); + } + + private static final class GetSystemProperties implements Callable,RuntimeException> { + public Map call() { + return new TreeMap(System.getProperties()); + } + private static final long serialVersionUID = 1L; + } + + public static Map getThreadDump(VirtualChannel channel) throws IOException, InterruptedException { + if(channel==null) + return Collections.singletonMap("N/A","N/A"); + return channel.call(new GetThreadDump()); + } + + private static final class GetThreadDump implements Callable,RuntimeException> { + public Map call() { + Map r = new LinkedHashMap(); + try { + for (ThreadInfo ti : Functions.getThreadInfos()) + r.put(ti.getThreadName(),Functions.dumpThreadInfo(ti)); + } catch (LinkageError _) { + // not in JDK6. fall back to JDK5 + r.clear(); + for (Map.Entry t : Thread.getAllStackTraces().entrySet()) { + StringBuffer buf = new StringBuffer(); + for (StackTraceElement e : t.getValue()) + buf.append(e).append('\n'); + r.put(t.getKey().getName(),buf.toString()); + } + } + return r; + } + private static final long serialVersionUID = 1L; + } + + /** + * Executes Groovy script remotely. + */ + public static String executeGroovy(String script, VirtualChannel channel) throws IOException, InterruptedException { + return channel.call(new Script(script)); + } + + private static final class Script implements Callable { + private final String script; + + private Script(String script) { + this.script = script; + } + + public String call() throws RuntimeException { + GroovyShell shell = new GroovyShell(); + + StringWriter out = new StringWriter(); + PrintWriter pw = new PrintWriter(out); + shell.setVariable("out", pw); + try { + Object output = shell.evaluate(script); + if(output!=null) + pw.println("Result: "+output); + } catch (Throwable t) { + t.printStackTrace(pw); + } + return out.toString(); + } + } +} diff --git a/core/src/main/resources/hudson/maven/MavenProbeAction/_script.jelly b/core/src/main/resources/hudson/maven/MavenProbeAction/_script.jelly new file mode 100644 index 0000000000..4b25e99660 --- /dev/null +++ b/core/src/main/resources/hudson/maven/MavenProbeAction/_script.jelly @@ -0,0 +1,8 @@ + + + +
println System.getenv("PATH")
+
+
diff --git a/core/src/main/resources/hudson/maven/MavenProbeAction/envVars.jelly b/core/src/main/resources/hudson/maven/MavenProbeAction/envVars.jelly new file mode 100644 index 0000000000..103f6ed3b2 --- /dev/null +++ b/core/src/main/resources/hudson/maven/MavenProbeAction/envVars.jelly @@ -0,0 +1,9 @@ + + + + +

${%Environment Variables}

+ +
+
+
diff --git a/core/src/main/resources/hudson/maven/MavenProbeAction/index.jelly b/core/src/main/resources/hudson/maven/MavenProbeAction/index.jelly new file mode 100644 index 0000000000..9fceaefd63 --- /dev/null +++ b/core/src/main/resources/hudson/maven/MavenProbeAction/index.jelly @@ -0,0 +1,11 @@ + + + + +
+ Obtain information about the running Maven process by clicking + links from the left. Often useful for trouble-shooting problems. +
+
+
+
diff --git a/core/src/main/resources/hudson/maven/MavenProbeAction/sidepanel.jelly b/core/src/main/resources/hudson/maven/MavenProbeAction/sidepanel.jelly new file mode 100644 index 0000000000..c6645e5b42 --- /dev/null +++ b/core/src/main/resources/hudson/maven/MavenProbeAction/sidepanel.jelly @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/core/src/main/resources/hudson/maven/MavenProbeAction/systemProperties.jelly b/core/src/main/resources/hudson/maven/MavenProbeAction/systemProperties.jelly new file mode 100644 index 0000000000..b6f1b30687 --- /dev/null +++ b/core/src/main/resources/hudson/maven/MavenProbeAction/systemProperties.jelly @@ -0,0 +1,10 @@ + + + + +

${%System Properties}

+ + +
+
+
diff --git a/core/src/main/resources/hudson/maven/MavenProbeAction/threads.jelly b/core/src/main/resources/hudson/maven/MavenProbeAction/threads.jelly new file mode 100644 index 0000000000..c1baa961b6 --- /dev/null +++ b/core/src/main/resources/hudson/maven/MavenProbeAction/threads.jelly @@ -0,0 +1,12 @@ + + + + +

Thread Dump

+ +

${t.key}

+
${t.value}
+
+
+
+
diff --git a/core/src/main/resources/hudson/maven/Messages.properties b/core/src/main/resources/hudson/maven/Messages.properties index 16c4d99604..fc83d8ba08 100644 --- a/core/src/main/resources/hudson/maven/Messages.properties +++ b/core/src/main/resources/hudson/maven/Messages.properties @@ -1,3 +1,5 @@ MavenModuleSet.DiplayName=Build a maven2 project (beta) -MavenModule.Pronoun=Module \ No newline at end of file +MavenModule.Pronoun=Module + +MavenProbeAction.DisplayName=Monitor Maven Process \ No newline at end of file diff --git a/core/src/main/resources/hudson/model/Hudson/_script.jelly b/core/src/main/resources/hudson/model/Hudson/_script.jelly index 4b26e5a851..2b3640d550 100644 --- a/core/src/main/resources/hudson/model/Hudson/_script.jelly +++ b/core/src/main/resources/hudson/model/Hudson/_script.jelly @@ -2,33 +2,7 @@ Called from doScript() to display the execution result and the form. --> - - - - -

Script Console

-

- Type in an arbitrary Groovy script and - execute it on the server. Useful for trouble-shooting and diagnostics. - Use the 'println' command to see the output (if you use System.out, - it will go to the server's stdout, which is harder to see.) Example: -

-
-println(hudson.model.Hudson.instance.pluginManager.plugins)
-      
-
- -
- -
- -
- -

Result

-
-
-
-
+ +
println(hudson.model.Hudson.instance.pluginManager.plugins)
+
diff --git a/core/src/main/resources/lib/hudson/scriptConsole.jelly b/core/src/main/resources/lib/hudson/scriptConsole.jelly new file mode 100644 index 0000000000..fc2bca7b9d --- /dev/null +++ b/core/src/main/resources/lib/hudson/scriptConsole.jelly @@ -0,0 +1,35 @@ + + + + + + +

${%Script Console}

+ +

+ Type in an arbitrary Groovy script and + execute it on the server. Useful for trouble-shooting and diagnostics. + Use the 'println' command to see the output (if you use System.out, + it will go to the server's stdout, which is harder to see.) Example: +

+ + + +
+ +
+ +
+ +
+ +

${%Result}

+
+
+
+
+
-- GitLab