diff --git a/src/main/java/org/jenkinsci/plugins/scriptler/builder/ScriptlerBuilder.java b/src/main/java/org/jenkinsci/plugins/scriptler/builder/ScriptlerBuilder.java index 09812cc..fa8ef80 100644 --- a/src/main/java/org/jenkinsci/plugins/scriptler/builder/ScriptlerBuilder.java +++ b/src/main/java/org/jenkinsci/plugins/scriptler/builder/ScriptlerBuilder.java @@ -35,6 +35,7 @@ import org.jenkinsci.plugins.scriptler.config.Parameter; import org.jenkinsci.plugins.scriptler.config.Script; import org.jenkinsci.plugins.scriptler.config.ScriptlerConfiguration; +import org.jenkinsci.plugins.scriptler.util.ControllerGroovyScript; import org.jenkinsci.plugins.scriptler.util.GroovyScript; import org.jenkinsci.plugins.scriptler.util.ScriptHelper; import org.jenkinsci.plugins.scriptler.util.UIHelper; @@ -246,7 +247,7 @@ public boolean perform(AbstractBuild build, Launcher launcher, BuildListen final Object output; if (script.onlyMaster) { // When run on master, make build, launcher, listener available to script - output = FilePath.localChannel.call(new GroovyScript(script.script, expandedParams, true, listener, launcher, build)); + output = FilePath.localChannel.call(new ControllerGroovyScript(script.script, expandedParams, true, listener, launcher, build)); } else { VirtualChannel channel = launcher.getChannel(); if (channel == null) { diff --git a/src/main/java/org/jenkinsci/plugins/scriptler/tokenmacro/ScriptlerTokenMacro.java b/src/main/java/org/jenkinsci/plugins/scriptler/tokenmacro/ScriptlerTokenMacro.java index 58b7895..eaae712 100644 --- a/src/main/java/org/jenkinsci/plugins/scriptler/tokenmacro/ScriptlerTokenMacro.java +++ b/src/main/java/org/jenkinsci/plugins/scriptler/tokenmacro/ScriptlerTokenMacro.java @@ -3,13 +3,15 @@ import hudson.Extension; import hudson.FilePath; import hudson.model.AbstractBuild; +import hudson.model.Node; import hudson.model.TaskListener; import hudson.remoting.Channel; import hudson.remoting.ChannelClosedException; -import hudson.remoting.VirtualChannel; +import jenkins.model.Jenkins; import org.jenkinsci.plugins.scriptler.Messages; import org.jenkinsci.plugins.scriptler.config.Script; +import org.jenkinsci.plugins.scriptler.util.ControllerGroovyScript; import org.jenkinsci.plugins.scriptler.util.GroovyScript; import org.jenkinsci.plugins.scriptler.util.ScriptHelper; import org.jenkinsci.plugins.tokenmacro.DataBoundTokenMacro; @@ -40,20 +42,18 @@ public String evaluate(AbstractBuild context, TaskListener listener, Strin throw new MacroEvaluationException(Messages.tokenmacro_AdminScriptOnly(scriptId)); } - VirtualChannel channel; - if (script.onlyMaster) { - channel = FilePath.localChannel; + Object output; + if (script.onlyMaster || Jenkins.get().equals(context.getBuiltOn())) { + output = FilePath.localChannel.call(new ControllerGroovyScript(script.script, Collections.emptyList(), true, listener, null, context)); } else { FilePath remoteFilePath = context.getWorkspace(); if (remoteFilePath == null) { // the remote node has apparently disconnected, so we can't run our script throw new ChannelClosedException((Channel) null, null); } - channel = remoteFilePath.getChannel(); + output = remoteFilePath.getChannel().call(new GroovyScript(script.script, Collections.emptyList(), true, listener)); } - Object output = channel.call(new GroovyScript(script.script, Collections.emptyList(), true, listener, null, context)); - return output != null ? output.toString() : ""; } diff --git a/src/main/java/org/jenkinsci/plugins/scriptler/util/ControllerGroovyScript.java b/src/main/java/org/jenkinsci/plugins/scriptler/util/ControllerGroovyScript.java new file mode 100644 index 0000000..abb21e0 --- /dev/null +++ b/src/main/java/org/jenkinsci/plugins/scriptler/util/ControllerGroovyScript.java @@ -0,0 +1,48 @@ +package org.jenkinsci.plugins.scriptler.util; + +import edu.umd.cs.findbugs.annotations.NonNull; +import groovy.lang.GroovyShell; +import hudson.Launcher; +import hudson.model.AbstractBuild; +import hudson.model.TaskListener; +import jenkins.model.Jenkins; +import org.jenkinsci.plugins.scriptler.config.Parameter; + +import java.util.Collection; + +public class ControllerGroovyScript extends GroovyScript { + private static final long serialVersionUID = 1L; + private transient final AbstractBuild build; + private transient final Launcher launcher; + + /** + * This constructor can only be used when the script is executed on the controller, because launcher and build can not be transferred to an agent and therefore the execution will fail + * @param script the script to be executed + * @param parameters the parameters to be passed to the script + * @param failWithException should the job fail with an exception + * @param listener access to logging via listener + * @param launcher the launcher + * @param build the current build + */ + public ControllerGroovyScript(String script, @NonNull Collection parameters, boolean failWithException, TaskListener listener, Launcher launcher, AbstractBuild build) { + super(script, parameters, failWithException, listener); + this.build = build; + this.launcher = launcher; + } + + @Override + public ClassLoader getClassLoader() { + return Jenkins.get().getPluginManager().uberClassLoader; + } + + @Override + protected void setShellVariables(@NonNull GroovyShell shell) { + super.setShellVariables(shell); + if (build != null) { + shell.setVariable("build", build); + } + if (launcher != null) { + shell.setVariable("launcher", launcher); + } + } +} diff --git a/src/main/java/org/jenkinsci/plugins/scriptler/util/GroovyScript.java b/src/main/java/org/jenkinsci/plugins/scriptler/util/GroovyScript.java index 20b44bc..0dbc092 100644 --- a/src/main/java/org/jenkinsci/plugins/scriptler/util/GroovyScript.java +++ b/src/main/java/org/jenkinsci/plugins/scriptler/util/GroovyScript.java @@ -3,17 +3,11 @@ import edu.umd.cs.findbugs.annotations.NonNull; import groovy.lang.GroovyShell; import groovy.lang.Script; -import hudson.Launcher; -import hudson.model.AbstractBuild; import hudson.model.TaskListener; -import jenkins.model.Jenkins; import jenkins.security.MasterToSlaveCallable; -import jenkins.security.Roles; import org.apache.commons.collections.map.LRUMap; import org.jenkinsci.plugins.scriptler.Messages; import org.jenkinsci.plugins.scriptler.config.Parameter; -import org.jenkinsci.remoting.Role; -import org.jenkinsci.remoting.RoleChecker; import java.io.PrintStream; import java.util.*; @@ -29,9 +23,6 @@ public class GroovyScript extends MasterToSlaveCallable parameters; private final boolean failWithException; private final TaskListener listener; - private transient final AbstractBuild build; - private transient final Launcher launcher; - private transient ClassLoader cl; @SuppressWarnings("unchecked") private static Map> cache = Collections.synchronizedMap(new LRUMap(10)); @@ -45,46 +36,26 @@ public class GroovyScript extends MasterToSlaveCallable parameters, boolean failWithException, TaskListener listener, Launcher launcher, AbstractBuild build) { + public GroovyScript(String script, @NonNull Collection parameters, boolean failWithException, TaskListener listener) { this.script = script; this.parameters = new ArrayList<>(parameters); this.failWithException = failWithException; this.listener = listener; - this.cl = getClassLoader(); - this.build = build; - this.launcher = launcher; - } - - /** - * Constructor - * @param script the script to be executed - * @param parameters the parameters to be passed to the script - * @param failWithException should the job fail with an exception - * @param listener access to logging via listener - */ - public GroovyScript(String script, @NonNull Collection parameters, boolean failWithException, TaskListener listener) { - this(script, parameters, failWithException, listener, null, null); } public ClassLoader getClassLoader() { - return Jenkins.get().getPluginManager().uberClassLoader; + return Thread.currentThread().getContextClassLoader(); } public Object call() { - // if we run locally, cl!=null. Otherwise the delegating classloader will be available as context classloader. - if (cl == null) { - cl = Thread.currentThread().getContextClassLoader(); - } PrintStream logger = listener.getLogger(); - GroovyShell shell = new GroovyShell(cl); + GroovyShell shell = new GroovyShell(getClassLoader()); for (Parameter param : parameters) { final String paramName = param.getName(); @@ -97,9 +68,7 @@ public Object call() { // set default variables shell.setVariable("out", logger); - shell.setVariable("listener", listener); - if(build != null) shell.setVariable("build", build); - if(launcher != null) shell.setVariable("launcher", launcher); + setShellVariables(shell); ConcurrentLinkedQueue