From bac87b1bf2eb41a04c66e350528e5054f9610ca6 Mon Sep 17 00:00:00 2001 From: Khai Do Date: Sat, 26 Jan 2013 10:00:22 -0800 Subject: [PATCH] fix gearman function registration bug The gearman function registration was registering functions on nodes multiple times. Added a check to make sure nodes on the label matched the node in the executor before registering the function. Also added better documentation and helper functions. Change-Id: Id13bbfe0c003a82e1e311736c5ff7a682e5efca1 --- .../plugins/gearman/ExecutorWorkerThread.java | 152 +++++++++++++----- 1 file changed, 111 insertions(+), 41 deletions(-) diff --git a/src/main/java/hudson/plugins/gearman/ExecutorWorkerThread.java b/src/main/java/hudson/plugins/gearman/ExecutorWorkerThread.java index f25b8cd..b1d8e6a 100644 --- a/src/main/java/hudson/plugins/gearman/ExecutorWorkerThread.java +++ b/src/main/java/hudson/plugins/gearman/ExecutorWorkerThread.java @@ -18,19 +18,21 @@ package hudson.plugins.gearman; -import hudson.model.Computer; import hudson.model.Label; import hudson.model.Node; import hudson.model.Project; +import java.util.HashSet; import java.util.List; import java.util.Scanner; +import java.util.Set; import jenkins.model.Jenkins; import org.slf4j.Logger; import org.slf4j.LoggerFactory; + /* * This is thread to run gearman executors * Executors are used to initiate jenkins builds @@ -48,9 +50,15 @@ public class ExecutorWorkerThread extends AbstractWorkerThread{ } - /* + + /** * This function finds the node with the corresponding node name Returns the * node if found, otherwise returns null + * + * @param name + * The name of the jenkins node. + * @return + * The jenkins node if found, otherwise null */ private Node findNode(String nodeName){ @@ -70,9 +78,79 @@ public class ExecutorWorkerThread extends AbstractWorkerThread{ public ExecutorWorkerThread(String host, int port, String name, Node node){ super(host, port, name); this.node = node; - } + + /** + * This function tokenizes the labels in a label string + * that is set in the jenkins projects + * + * @param label + * The label string. + * @param pattern + * The pattern for tokenizing the label. + * @return + * A list of labels, the list can be empty + */ + private Set tokenizeLabelString(String label, String pattern) { + + Set labelSet = new HashSet(); + + if (pattern == null) { + return labelSet; + } + + if (pattern.isEmpty()) { + return labelSet; + } + + if (label != null) { + + // String projectLabelString = label.getExpression(); + Scanner slabel = new Scanner(label); + try { + slabel.useDelimiter(pattern); + while (slabel.hasNext()) { + String newLabel = slabel.next(); + labelSet.add(newLabel); + + } + } finally { + slabel.close(); + } + } + return labelSet; + } + + /** + * Register gearman functions on this node. This will unregister all + * functions before registering new functions. + * + * How functions are registered: + * - If the project has no label then we register the project with all + * nodes + * + * build:pep8 on precise-123 + * build:pep8 on precise-129 + * build:pep8 on oneiric-456 + * + * - If the project contains one label then we register with the node + * that contains the corresponding label. Labels with '&&' is + * considered just one label + * + * build:pep8:precise on precise-123 + * build:pep8:precise on precise-129 + * build:pep8:precise on precise-134 + * + * - If the project contains multiple labels seperated by '||' then + * we register with the nodes that contain the corresponding labels + * + * build:pep8:precise on precise-123 + * build:pep8:precise on precise-129 + * build:pep8:oneiric on oneiric-456 + * build:pep8:oneiric on oneiric-459 + * + */ @Override public void registerJobs() { @@ -93,49 +171,41 @@ public class ExecutorWorkerThread extends AbstractWorkerThread{ // List projects = // jenkins.getAllItems(AbstractProject.class); for (Project project : allProjects) { + + if (project.isDisabled()) { // ignore all disabled projects + continue; + } + String projectName = project.getName(); + Label label = project.getAssignedLabel(); - // ignore all disabled projects - if (!project.isDisabled()) { + if (label == null) { // project has no label -> so register + // "build:projectName" on all nodes + String jobFunctionName = "build:" + projectName; + logger.info("Registering job " + jobFunctionName + " on " + + this.node.getNodeName()); + worker.registerFunctionFactory(new CustomGearmanFunctionFactory( + jobFunctionName, StartJobWorker.class.getName(), + project, this.node)); - Label label = project.getAssignedLabel(); + } else { // register "build:projectName:nodeName" on the + // node that has a matching label - if (label == null) { // project has no label -> so register - // "build:projectName" - String jobFunctionName = "build:" + projectName; - logger.info("Registering job " + jobFunctionName + " on " - + node.getNodeName()); - worker.registerFunctionFactory(new CustomGearmanFunctionFactory( - jobFunctionName, StartJobWorker.class.getName(), - project, node)); + Set projectLabelNodes = label.getNodes(); + String projectLabelString = label.getExpression(); + Set projectLabels = tokenizeLabelString( + projectLabelString, "\\|\\|"); - } else { // register "build:projectName:nodeName" - - // make sure node is online - Computer c = node.toComputer(); - boolean nodeOnline = c.isOnline(); - - if (nodeOnline) { - // get and iterate thru them to build the functions - // to register with the worker - String projectLabelString = label.getExpression(); - Scanner projectLabels = new Scanner(projectLabelString); - try { - projectLabels.useDelimiter("\\|\\|"); - while (projectLabels.hasNext()) { - String projectLabel = projectLabels.next(); - String jobFunctionName = "build:" + projectName - + ":" + projectLabel; - logger.info("Registering job " - + jobFunctionName + " on " - + node.getNodeName()); - worker.registerFunctionFactory(new CustomGearmanFunctionFactory( - jobFunctionName, StartJobWorker.class - .getName(), project, node)); - } - } finally { - projectLabels.close(); - } + // iterate thru all project labels and find matching nodes + for (String projectLabel : projectLabels) { + if (projectLabelNodes.contains(this.node)) { + String jobFunctionName = "build:" + projectName + + ":" + projectLabel; + logger.info("Registering job " + jobFunctionName + + " on " + this.node.getNodeName()); + worker.registerFunctionFactory(new CustomGearmanFunctionFactory( + jobFunctionName, StartJobWorker.class + .getName(), project, this.node)); } } }