Skip to content

Commit

Permalink
Switch to built-in node instead of controller
Browse files Browse the repository at this point in the history
The comment about running Scriptler scripts on the controller is
somewhat incorrect and we should be talking about running on the built-
in node instead. Make this change, as well as in the configuration data.
  • Loading branch information
mtughan committed Dec 2, 2024
1 parent 84f45f8 commit 28b28ff
Show file tree
Hide file tree
Showing 14 changed files with 91 additions and 54 deletions.
36 changes: 36 additions & 0 deletions src/main/java/org/jenkinsci/plugins/scriptler/NodeNames.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package org.jenkinsci.plugins.scriptler;

import edu.umd.cs.findbugs.annotations.NonNull;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public final class NodeNames {
public static final String BUILT_IN = "(built-in)";
public static final String ALL = "(all)";
public static final String ALL_AGENTS = "(all agents)";
private static final Map<String, String> DEPRECATED_ALIASES;

static {
Map<String, List<String>> deprecatedNames =
Map.of(BUILT_IN, List.of("(master)", "(controller)"), ALL_AGENTS, List.of("(all slaves)"));

Map<String, String> aliases = new HashMap<>();
deprecatedNames.forEach(
(newName, oldNames) -> oldNames.forEach(oldName -> aliases.put(normalizeName(oldName), newName)));

DEPRECATED_ALIASES = Map.copyOf(aliases);
}

@NonNull
private static String normalizeName(@NonNull String name) {
return name.toLowerCase();
}

@NonNull
public static String normalizeNodeName(@NonNull String nodeName) {
return DEPRECATED_ALIASES.getOrDefault(normalizeName(nodeName), nodeName);
}

private NodeNames() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,6 @@ public class ScriptlerManagement extends ManagementLink implements RootAction {
private static final String NOT_APPROVED_YET = "notApprovedYet";
private static final String CAN_BYPASS_APPROVAL = "canByPassScriptApproval";
private static final String SCRIPT = "script";
private static final String MASTER = "(master)";
private static final String CONTROLLER = "(controller)";
private static final String ALL = "(all)";
private static final String ALL_SLAVES = "(all slaves)";
private static final String ALL_AGENTS = "(all agents)";

private static final MarkupFormatter INSTANCE = RawHtmlMarkupFormatter.INSTANCE;

Expand Down Expand Up @@ -244,8 +239,8 @@ public HttpResponse doDownloadScript(
* script code
* @param nonAdministerUsing
* allow usage in Scriptler build step
* @param onlyController
* this script is only allowed to run on the controller
* @param onlyBuiltIn
* this script is only allowed to run on the built-in node
* @param originCatalogName
* (optional) the name of the catalog the script is loaded/added from
* @param originId
Expand All @@ -261,7 +256,7 @@ public HttpResponse doScriptAdd(
@QueryParameter("comment") String comment,
@QueryParameter(SCRIPT) String script,
@QueryParameter("nonAdministerUsing") boolean nonAdministerUsing,
@QueryParameter("onlyController") boolean onlyController,
@QueryParameter("onlyBuiltIn") boolean onlyBuiltIn,
String originCatalogName,
String originId)
throws IOException, ServletException {
Expand All @@ -271,7 +266,7 @@ public HttpResponse doScriptAdd(
List<Parameter> parameters = UIHelper.extractParameters(req.getSubmittedForm());

saveScriptAndForward(
id, name, comment, script, nonAdministerUsing, onlyController, originCatalogName, originId, parameters);
id, name, comment, script, nonAdministerUsing, onlyBuiltIn, originCatalogName, originId, parameters);
return new HttpRedirect(INDEX);
}

Expand All @@ -286,7 +281,7 @@ private String saveScriptAndForward(
String comment,
String script,
boolean nonAdministerUsing,
boolean onlyController,
boolean onlyBuiltIn,
String originCatalogName,
String originId,
@NonNull List<Parameter> parameters)
Expand Down Expand Up @@ -330,7 +325,7 @@ private String saveScriptAndForward(
parameters);
} else {
// save (overwrite) the meta information
newScript = new Script(finalFileName, displayName, comment, nonAdministerUsing, parameters, onlyController);
newScript = new Script(finalFileName, displayName, comment, nonAdministerUsing, parameters, onlyBuiltIn);
}
ScriptlerConfiguration cfg = getConfiguration();
cfg.addOrReplace(newScript);
Expand Down Expand Up @@ -520,7 +515,7 @@ public void doRunScript(StaplerRequest2 req, StaplerResponse2 rsp, @QueryParamet

req.setAttribute(SCRIPT, script);
// set default selection
req.setAttribute("currentNode", CONTROLLER);
req.setAttribute("currentNode", NodeNames.BUILT_IN);
req.getView(this, "runScript.jelly").forward(req, rsp);
}

Expand Down Expand Up @@ -603,7 +598,7 @@ public void doTriggerScript(
* @param script
* the script code (groovy)
* @param node
* the node, to execute the code on, defaults to {@value #CONTROLLER}
* the node, to execute the code on, defaults to {@value NodeNames#BUILT_IN}
* @param contentType
* the contentType to use in the response, defaults to text/plain
*/
Expand Down Expand Up @@ -653,7 +648,7 @@ public void doRun(

rsp.setContentType(contentType == null ? "text/plain" : contentType);

final List<String> computers = resolveComputerNames(node == null ? CONTROLLER : node);
final List<String> computers = resolveComputerNames(node == null ? NodeNames.BUILT_IN : node);
if (computers.size() > 1) {
rsp.getOutputStream().print(ScriptHelper.runScript(computers, script, paramArray));
} else {
Expand All @@ -678,17 +673,14 @@ private Collection<Parameter> prepareParameters(StaplerRequest2 req, Script temp
return params.values();
}

private List<String> resolveComputerNames(String nameAlias) {
private List<String> resolveComputerNames(String rawNameAlias) {
final String nameAlias = NodeNames.normalizeNodeName(rawNameAlias);
final List<String> computers;
if (nameAlias.equalsIgnoreCase(ALL)
|| nameAlias.equalsIgnoreCase(ALL_AGENTS)
|| nameAlias.equalsIgnoreCase(ALL_SLAVES)) {
if (nameAlias.equalsIgnoreCase(NodeNames.ALL) || nameAlias.equalsIgnoreCase(NodeNames.ALL_AGENTS)) {
computers = getComputerNames();
if (nameAlias.equalsIgnoreCase(ALL)) {
computers.add(CONTROLLER);
if (nameAlias.equalsIgnoreCase(NodeNames.ALL)) {
computers.add(NodeNames.BUILT_IN);
}
} else if (nameAlias.equalsIgnoreCase(MASTER)) {
computers = List.of(CONTROLLER);
} else {
computers = List.of(nameAlias);
}
Expand Down Expand Up @@ -765,18 +757,18 @@ public List<String> getSlaveAlias(Script script) {
* @return list with all computer names
*/
public List<String> getComputerAliases(Script script) {
if (script.onlyController) {
return List.of(CONTROLLER);
if (script.onlyBuiltIn) {
return List.of(NodeNames.BUILT_IN);
}
final List<String> computerNames = getComputerNames();
// add 'magic' name for the controller, so all nodes can be handled the same way
computerNames.addAll(0, List.of(CONTROLLER, ALL, ALL_AGENTS));
// add 'magic' name for the built-in node, so all nodes can be handled the same way
computerNames.addAll(0, List.of(NodeNames.BUILT_IN, NodeNames.ALL, NodeNames.ALL_AGENTS));
return computerNames;
}

private List<String> getComputerNames() {
return Arrays.stream(Jenkins.get().getComputers())
// remove the controller's computer as it has an empty name
// remove the built-in's computer as it has an empty name
.filter(Predicate.not(Jenkins.MasterComputer.class::isInstance))
.map(Computer::getName)
.collect(Collectors.toCollection(ArrayList::new));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -255,8 +255,8 @@ public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListen
parameter.getName(), TokenMacro.expandAll(build, listener, parameter.getValue())));
}
final Object output;
if (script.onlyController) {
// When run on controller, make build, launcher, listener available to script
if (script.onlyBuiltIn) {
// When run on the built-in node, make build, launcher, listener available to script
output = FilePath.localChannel.call(new ControllerGroovyScript(
script.getScriptText(), expandedParams, true, listener, launcher, build));
} else {
Expand Down
37 changes: 22 additions & 15 deletions src/main/java/org/jenkinsci/plugins/scriptler/config/Script.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,17 @@ public class Script implements Comparable<Script>, NamedResource, Serializable {
// User with Scriptler/RUN_SCRIPT permission can add/edit Scriptler step in projects
public final boolean nonAdministerUsing;

// script is runnable only on controller
public final boolean onlyController;
// script is runnable only on the built-in node
public final boolean onlyBuiltIn;

/**
* @deprecated Use {@link #onlyController} instead.
* @deprecated Use {@link #onlyBuiltIn} instead.
*/
@Deprecated(since = "386")
public final Boolean onlyController;

/**
* @deprecated Use {@link #onlyBuiltIn} instead.
*/
@Deprecated(since = "381")
public final Boolean onlyMaster;
Expand All @@ -72,15 +78,15 @@ public Script(
String comment,
boolean nonAdministerUsing,
@NonNull List<Parameter> parameters,
boolean onlyController) {
this(id, name, comment, true, null, null, null, nonAdministerUsing, parameters, onlyController);
boolean onlyBuiltIn) {
this(id, name, comment, true, null, null, null, nonAdministerUsing, parameters, onlyBuiltIn);
}

/**
* used during plugin start to synchronize available scripts
*/
public Script(String id, String comment, boolean available, boolean nonAdministerUsing, boolean onlyController) {
this(id, id, comment, available, null, null, null, nonAdministerUsing, Collections.emptyList(), onlyController);
public Script(String id, String comment, boolean available, boolean nonAdministerUsing, boolean onlyBuiltIn) {
this(id, id, comment, available, null, null, null, nonAdministerUsing, List.of(), onlyBuiltIn);
}

/**
Expand Down Expand Up @@ -112,7 +118,7 @@ public Script(
String originDate,
boolean nonAdministerUsing,
@NonNull List<Parameter> parameters,
boolean onlyController) {
boolean onlyBuiltIn) {
this(
id,
name,
Expand All @@ -123,7 +129,7 @@ public Script(
originDate,
nonAdministerUsing,
parameters,
onlyController);
onlyBuiltIn);
}

/**
Expand All @@ -139,7 +145,7 @@ public Script(
String originDate,
boolean nonAdministerUsing,
@NonNull List<Parameter> parameters,
boolean onlyController) {
boolean onlyBuiltIn) {
this.id = id;
this.name = name;
this.comment = comment;
Expand All @@ -149,8 +155,8 @@ public Script(
this.originDate = originDate;
this.nonAdministerUsing = nonAdministerUsing;
this.parameters = new ArrayList<>(parameters);
this.onlyController = onlyController;
this.onlyMaster = null;
this.onlyBuiltIn = onlyBuiltIn;
this.onlyMaster = this.onlyController = null;
}

public Script copy() {
Expand All @@ -164,7 +170,7 @@ public Script copy() {
originDate,
nonAdministerUsing,
parameters,
onlyController);
onlyBuiltIn);
}

/*
Expand Down Expand Up @@ -239,7 +245,8 @@ public int compareTo(Script o) {

@Serial
public Object readResolve() {
if (onlyMaster != null) {
if (onlyMaster != null || onlyController != null) {
boolean onlyBuiltIn = onlyMaster == null ? onlyController : onlyMaster;
return new Script(
id,
name,
Expand All @@ -250,7 +257,7 @@ public Object readResolve() {
originDate,
nonAdministerUsing,
parameters,
onlyMaster);
onlyBuiltIn);
}
return this;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ private Script merge(Script origin, Script newScript) {
originDate,
newScript.nonAdministerUsing,
newScript.getParameters(),
newScript.onlyController);
newScript.onlyBuiltIn);
}

public final Set<Script> getScripts() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public String evaluate(AbstractBuild<?, ?> context, TaskListener listener, Strin
String scriptText = script.getScriptText();
VirtualChannel channel;
GroovyScript groovyScript;
if (script.onlyController || Jenkins.get().equals(context.getBuiltOn())) {
if (script.onlyBuiltIn || Jenkins.get().equals(context.getBuiltOn())) {
channel = FilePath.localChannel;
groovyScript = new ControllerGroovyScript(scriptText, List.of(), true, listener, null, context);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ public class ControllerGroovyScript extends GroovyScript {
private final transient 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
* This constructor can only be used when the script is executed on the built-in node, 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import net.sf.json.JSONObject;
import net.sf.json.JSONSerializer;
import org.jenkinsci.plugins.scriptler.Messages;
import org.jenkinsci.plugins.scriptler.NodeNames;
import org.jenkinsci.plugins.scriptler.ScriptlerManagement;
import org.jenkinsci.plugins.scriptler.config.Parameter;
import org.jenkinsci.plugins.scriptler.config.Script;
Expand Down Expand Up @@ -170,7 +171,7 @@ public static String runScript(String node, String scriptTxt, @NonNull Collectio
try {
Computer comp = Jenkins.get().getComputer(node);
TaskListener listener = new StreamTaskListener(sos, StandardCharsets.UTF_8);
if (comp == null && "(controller)".equals(node)) {
if (comp == null && NodeNames.BUILT_IN.equals(node)) {
FilePath.localChannel.call(new GroovyScript(scriptTxt, parameters, false, listener));
} else if (comp != null && comp.getChannel() != null) {
comp.getChannel().call(new GroovyScript(scriptTxt, parameters, false, listener));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
# THE SOFTWARE.

display_name=Scriptler
description=Store/edit/run scripts on any of the agents or the controller.
description=Store/edit/run scripts on any of the agents or the built-in node.
scriptdirectorytitle=The scripts are stored at:
not_groovy_script=this is not a groovy script: {0}
script_loaded_from_directory=this script was discovered on the file system, please describe it!
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ THE SOFTWARE.
<f:checkbox name="nonAdministerUsing" checked="${script.nonAdministerUsing}" />
</f:entry>
<f:entry title="${%Restriction}" description="${%RestrictionDescription}">
<f:checkbox name="onlyController" checked="${script.onlyController}" />
<f:checkbox name="onlyBuiltIn" checked="${script.onlyBuiltIn}" />
</f:entry>
<f:block>
<div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ uploadtext=Select a Groovy script from your local system to be uploaded this wil
Permission = Allow usage in build step
PermissionDescription = Allow usage of the script as a Scriptler build step
Restriction = Restriction
RestrictionDescription = Script is always executed on the controller
RestrictionDescription = Script is always executed on the built-in node
Comment=Comment
ParametersDescription=Define script parameters
Parameters=Parameters
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
<f:checkbox name="nonAdministerUsing" />
</f:entry>
<f:entry title="${%Restriction}" description="${%RestrictionDescription}">
<f:checkbox name="onlyController" checked="${script.onlyController}" />
<f:checkbox name="onlyBuiltIn" checked="${script.onlyBuiltIn}" />
</f:entry>
<f:entry title="${%Script}">
<textarea id="script" name="script" class="${h.isUnitTest ? '' : 'script'}"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ uploadtext=Select a Groovy script from your local system to be uploaded (*.groov
UploadEncoding=Uploaded files should be encoded with UTF-8.
Permission = Allow usage in build step
Restriction = Restriction
RestrictionDescription = Script is always executed on the controller
RestrictionDescription = Script is always executed on the built-in node
Example=Example:
Name=Name
Comment=Comment
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
<j:jelly xmlns:j="jelly:core">
<dt>$${SCRIPTLER, scriptId="SCRIPT_ID"}</dt>
<dd>
Expands to the <i>return value</i> of the Scriptler script. The script must have the "Permission" box checked. If the script attempts to use the <i>build</i> parameter, it must have the "Restriction" box checked, for the execution to be restricted to the controller.
Expands to the <i>return value</i> of the Scriptler script. The script must have the "Permission" box checked. If the script attempts to use the <i>build</i> parameter, it must have the "Restriction" box checked, for the execution to be restricted to the built-in node.
</dd>
</j:jelly>

0 comments on commit 28b28ff

Please sign in to comment.