Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[FIXED JENKINS-21194] add notion of NodeEligibility to differentiate …
…between different offline modes of nodes
  • Loading branch information
imod committed Jan 12, 2014
1 parent 306a5a2 commit c84f714
Show file tree
Hide file tree
Showing 24 changed files with 683 additions and 301 deletions.
Expand Up @@ -3,37 +3,41 @@
*/
package org.jvnet.jenkins.plugins.nodelabelparameter;

import java.util.Collection;
import java.util.Set;

import javax.servlet.ServletException;

import hudson.Extension;
import hudson.Launcher;
import hudson.model.AbstractBuild;
import hudson.model.AutoCompletionCandidates;
import hudson.model.BuildListener;
import hudson.model.ParameterValue;
import hudson.model.AbstractBuild;
import hudson.model.Label;
import hudson.model.Node;
import hudson.model.ParameterDefinition;
import hudson.model.labels.LabelExpression;
import hudson.util.FormValidation;

import java.util.Collection;
import java.util.Set;

import javax.servlet.ServletException;

import jenkins.model.Jenkins;
import net.sf.json.JSONObject;

import org.apache.commons.lang.StringUtils;
import org.jvnet.jenkins.plugins.nodelabelparameter.node.AllNodeEligibility;
import org.jvnet.jenkins.plugins.nodelabelparameter.node.IgnoreOfflineNodeEligibility;
import org.jvnet.jenkins.plugins.nodelabelparameter.node.NodeEligibility;
import org.jvnet.jenkins.plugins.nodelabelparameter.wrapper.TriggerNextBuildWrapper;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.StaplerRequest;

import antlr.ANTLRException;

import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.collect.Collections2;

import antlr.ANTLRException;

/**
* Defines a build parameter used to restrict the node a job will be executed
* on. Such a label works exactly the same way as if you would define it in the
Expand All @@ -46,16 +50,31 @@ public class LabelParameterDefinition extends ParameterDefinition implements Mul

public final String defaultValue;
private boolean allNodesMatchingLabel;
private boolean ignoreOfflineNodes;
@Deprecated
private transient boolean ignoreOfflineNodes;
private String triggerIfResult;


private NodeEligibility nodeEligibility;

@DataBoundConstructor
public LabelParameterDefinition(String name, String description, String defaultValue, boolean allNodesMatchingLabel, NodeEligibility nodeEligibility, String triggerIfResult) {
super(name, description);
this.defaultValue = defaultValue;
this.allNodesMatchingLabel = allNodesMatchingLabel;
this.nodeEligibility = nodeEligibility == null ? new AllNodeEligibility() : nodeEligibility;
this.triggerIfResult = StringUtils.isBlank(triggerIfResult) ? Constants.ALL_CASES : triggerIfResult;
}

@Deprecated
public LabelParameterDefinition(String name, String description, String defaultValue, boolean allNodesMatchingLabel, boolean ignoreOfflineNodes, String triggerIfResult) {
super(name, description);
this.defaultValue = defaultValue;
this.allNodesMatchingLabel = allNodesMatchingLabel;
this.ignoreOfflineNodes = ignoreOfflineNodes;
if(ignoreOfflineNodes) {
this.nodeEligibility = new IgnoreOfflineNodeEligibility();
} else {
this.nodeEligibility = new AllNodeEligibility();
}
this.triggerIfResult = StringUtils.isBlank(triggerIfResult) ? Constants.ALL_CASES : triggerIfResult;
}

Expand Down Expand Up @@ -83,8 +102,8 @@ public boolean isAllNodesMatchingLabel() {
return allNodesMatchingLabel;
}

public boolean isIgnoreOfflineNodes() {
return ignoreOfflineNodes;
public NodeEligibility getNodeEligibility() {
return nodeEligibility;
}

@Extension
Expand Down Expand Up @@ -161,14 +180,20 @@ private Set<Node> getNodesForLabel(String labelExp) throws ANTLRException {
Label label = LabelExpression.parseExpression(labelExp);
return label.getNodes();
}

/**
* provides the default node eligibility for the UI
*/
public NodeEligibility getDefaultNodeEligibility() {
return new AllNodeEligibility();
}

/**
* function providing the node description for UI when listing matching nodes
*/
private static final class NodeDescFunction implements Function<Node, String> {
public String apply(Node n) {
final String nodeName = StringUtils.isBlank(n.getNodeName()) ? Constants.MASTER : n.getNodeName();
return nodeName + (NodeUtil.isNodeOnline(nodeName) ? "" : " (offline)");
return StringUtils.isBlank(n.getNodeName()) ? Constants.MASTER : n.getNodeName();
}
}
}
Expand All @@ -193,7 +218,7 @@ public final ParameterValue createValue(StaplerRequest req) {
} else if (value.length != 1) {
throw new IllegalArgumentException("Illegal number of parameter values for " + getName() + ": " + value.length);
}
return new LabelParameterValue(getName(), value[0], allNodesMatchingLabel, ignoreOfflineNodes);
return new LabelParameterValue(getName(), value[0], allNodesMatchingLabel, nodeEligibility);
}

public String getTriggerIfResult() {
Expand Down
Expand Up @@ -24,7 +24,8 @@
import java.util.logging.Logger;

import org.apache.commons.lang.StringUtils;
import org.jvnet.jenkins.plugins.nodelabelparameter.wrapper.TriggerNextBuildWrapper;
import org.jvnet.jenkins.plugins.nodelabelparameter.node.AllNodeEligibility;
import org.jvnet.jenkins.plugins.nodelabelparameter.node.NodeEligibility;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.export.Exported;

Expand Down Expand Up @@ -52,19 +53,19 @@ public LabelParameterValue(String name) {

@Deprecated
public LabelParameterValue(String name, String label) {
this(name, label, false, false);
this(name, label, false, new AllNodeEligibility());
}

public LabelParameterValue(String name, List<String> labels, boolean ignoreOfflineNodes) {
public LabelParameterValue(String name, List<String> labels, NodeEligibility nodeEligibility) {
super(name);
setNextLabels(labels, ignoreOfflineNodes);
setNextLabels(labels, nodeEligibility);
}

/**
* @param name
*/
@DataBoundConstructor
public LabelParameterValue(String name, String label, boolean allNodesMatchingLabel, boolean ignoreOfflineNodes) {
public LabelParameterValue(String name, String label, boolean allNodesMatchingLabel, NodeEligibility nodeEligibility) {
super(nameOrDefault(name));
if (label != null) {
this.label = label.trim();
Expand All @@ -76,58 +77,40 @@ public LabelParameterValue(String name, String label, boolean allNodesMatchingLa
// we are not able to determine a node for the given label - let Jenkins inform the user about it, by placing the job into the queue
labels.add(label);
}
setNextLabels(labels, ignoreOfflineNodes);
setNextLabels(labels, nodeEligibility);
}
}

private void setNextLabels(List<String> labels, boolean ignoreOfflineNodes) {
private void setNextLabels(List<String> labels, NodeEligibility nodeEligibility) {
if (labels != null && !labels.isEmpty()) {

List<String> tmpLabels = new ArrayList<String>(labels);

List<String> tmpLabels = new ArrayList<String>(labels);
nextLabels = new ArrayList<String>();
if (ignoreOfflineNodes) {
for (String nodeName : tmpLabels) {
nodeName = nodeName.trim();
if (NodeUtil.isNodeOnline(nodeName)) {
if (getLabel() == null) {
this.setLabel(nodeName);
} else {
nextLabels.add(nodeName);
}

for (String nodeName : tmpLabels) {
if (nodeEligibility.isEligible(nodeName)) {
if (getLabel() == null && NodeUtil.isNodeOnline(nodeName)) {
// search for the first online node we can use, otherwise we might get needlessly stuck in the queue before we even start the first job
this.setLabel(nodeName.trim());
} else {
LOGGER.fine(Messages.NodeListBuildParameterFactory_skippOfflineNode(nodeName));
nextLabels.add(nodeName);
}
}
} else {

// search for the first online node we can use, otherwise we might get needlessly stuck in the queue before we even start the first job
String firstOnlineNodeName = null;
for (String nodeName : tmpLabels) {
if (NodeUtil.isNodeOnline(nodeName.trim())) {
firstOnlineNodeName = nodeName;
break;
}
}

if (firstOnlineNodeName == null) {
// we did not find an online node, therefore we use the first entry in the requested list
firstOnlineNodeName = tmpLabels.remove(0);
} else {
tmpLabels.remove(firstOnlineNodeName);
LOGGER.fine(Messages.NodeListBuildParameterFactory_skippOfflineNode(nodeName));
}
this.setLabel(firstOnlineNodeName.trim());
nextLabels.addAll(tmpLabels);
}

if (getLabel() == null) {
// we did not find an online node, therefore we use the first entry in the requested list
if(!nextLabels.isEmpty()) {
this.setLabel(nextLabels.remove(0).trim());
}
}

}
if (getLabel() == null || getLabel().length() == 0) {
// these artificial labels will cause the job to stay in the queue and the user will see this label
if (ignoreOfflineNodes) {
setLabel(Messages.LabelParameterValue_triggerWithoutValidOnlineNode(StringUtils.join(labels, ',')));
} else {
setLabel(Messages.LabelParameterValue_triggeredButNoNodeGiven());
}
if (StringUtils.isBlank(getLabel())) {

This comment has been minimized.

Copy link
@oleg-nenashev

oleg-nenashev May 7, 2014

Member

@imod
Together with checks above, this setLabel() call leads to https://issues.jenkins-ci.org/browse/JENKINS-22226

// these artificial label will cause the job to stay in the queue and the user will see this label
setLabel(Messages.LabelParameterValue_triggerWithoutValidOnlineNode(StringUtils.join(labels, ',')));
}
}

Expand Down Expand Up @@ -225,18 +208,9 @@ public BuildWrapper createBuildWrapper(AbstractBuild<?, ?> build) {
if (property != null) {
final List<ParameterDefinition> parameterDefinitions = property.getParameterDefinitions();
for (ParameterDefinition paramDef : parameterDefinitions) {
if(MultipleNodeDescribingParameterDefinition.class.isInstance(paramDef)) {
return ((MultipleNodeDescribingParameterDefinition)paramDef).createBuildWrapper();
if (MultipleNodeDescribingParameterDefinition.class.isInstance(paramDef)) {
return ((MultipleNodeDescribingParameterDefinition) paramDef).createBuildWrapper();
}
// if (paramDef instanceof LabelParameterDefinition) {
// final LabelParameterDefinition labelParameterDefinition = (LabelParameterDefinition) paramDef;
// if (labelParameterDefinition.isAllNodesMatchingLabel()) {
// // we expect only one node parameter definition per job
// return new TriggerNextBuildWrapper(labelParameterDefinition);
// } else {
// return null;
// }
// }
}
}
return null;
Expand Down
@@ -1,5 +1,6 @@
package org.jvnet.jenkins.plugins.nodelabelparameter;

import org.jvnet.jenkins.plugins.nodelabelparameter.node.NodeEligibility;
import org.jvnet.jenkins.plugins.nodelabelparameter.wrapper.TriggerNextBuildWrapper;

import hudson.Launcher;
Expand Down Expand Up @@ -27,11 +28,11 @@ public interface MultipleNodeDescribingParameterDefinition {
public String getName();

/**
* Should a build be triggered for nodes currently offline
* gets the strategy which decides whether a node should be ignored or not
*
* @return <code>true</code> if offline nodes should be ignored
* @return the eligibility definition
*/
public boolean isIgnoreOfflineNodes();
public NodeEligibility getNodeEligibility();

/**
* Callback to allow the parameter definition to do a final validation if everything is OK to proceed. Implementations are asked to throw a runtime exception if something is not OK and the build
Expand Down

0 comments on commit c84f714

Please sign in to comment.