The jenkins gearman plugin
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ExecutorWorkerThread.java 7.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. /*
  2. *
  3. * Copyright 2013 Hewlett-Packard Development Company, L.P.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. */
  18. package hudson.plugins.gearman;
  19. import hudson.model.AbstractProject;
  20. import hudson.model.Computer;
  21. import hudson.model.Label;
  22. import hudson.model.labels.LabelAtom;
  23. import hudson.model.Node;
  24. import hudson.model.Node.Mode;
  25. import java.util.HashMap;
  26. import java.util.HashSet;
  27. import java.util.List;
  28. import java.util.Scanner;
  29. import java.util.Set;
  30. import jenkins.model.Jenkins;
  31. import org.gearman.worker.GearmanFunctionFactory;
  32. import org.slf4j.Logger;
  33. import org.slf4j.LoggerFactory;
  34. /*
  35. * This is the thread to run gearman executors
  36. * Executors are used to initiate jenkins builds
  37. *
  38. * @author Khai Do
  39. *
  40. */
  41. public class ExecutorWorkerThread extends AbstractWorkerThread{
  42. private static final Logger logger = LoggerFactory
  43. .getLogger(Constants.PLUGIN_LOGGER_NAME);
  44. private final Computer computer;
  45. private final String masterName;
  46. private HashMap<String,GearmanFunctionFactory> functionMap;
  47. // constructor
  48. public ExecutorWorkerThread(String host, int port, String name,
  49. Computer computer, String masterName,
  50. AvailabilityMonitor availability) {
  51. super(host, port, name, availability);
  52. this.computer = computer;
  53. this.masterName = masterName;
  54. }
  55. @Override
  56. protected void initWorker() {
  57. availability.unlock(worker);
  58. super.initWorker();
  59. this.functionMap = new HashMap<String,GearmanFunctionFactory>();
  60. }
  61. /**
  62. * Register gearman functions on this computer. This will unregister all
  63. * functions before registering new functions. Works for free-style
  64. * and maven projects but does not work for multi-config projects
  65. *
  66. * How functions are registered:
  67. * - If the project has no label then we register the project with all
  68. * computers
  69. *
  70. * build:pep8 on precise-123
  71. * build:pep8 on oneiric-456
  72. *
  73. * - If the project contains one label then we register with the computer
  74. * that contains the corresponding label. Labels with '&&' is
  75. * considered just one label
  76. *
  77. * build:pep8:precise on precise-123
  78. * build:pep8 on precise-123
  79. * build:pep8:precise on precise-129
  80. * build:pep8 on precise-129
  81. *
  82. * - If the project contains multiple labels separated by '||' then
  83. * we register with the computers that contain the corresponding labels
  84. *
  85. * build:pep8:precise on precise-123
  86. * build:pep8 on precise-123
  87. * build:pep8:precise on precise-129
  88. * build:pep8 on precise-129
  89. * build:pep8:oneiric on oneiric-456
  90. * build:pep8 on oneiric-456
  91. * build:pep8:oneiric on oneiric-459
  92. * build:pep8 on oneiric-459
  93. *
  94. */
  95. @Override
  96. public void registerJobs() {
  97. if (worker == null || functionMap == null) {
  98. // We haven't been initialized yet; the run method will call this again
  99. return;
  100. }
  101. HashMap<String,GearmanFunctionFactory> newFunctionMap = new HashMap<String,GearmanFunctionFactory>();
  102. if (!computer.isOffline()) {
  103. Node node = computer.getNode();
  104. List<AbstractProject> allProjects = Jenkins.getActiveInstance().getAllItems(AbstractProject.class);
  105. for (AbstractProject<?, ?> project : allProjects) {
  106. if (project.isDisabled()) { // ignore all disabled projects
  107. continue;
  108. }
  109. String projectName = project.getName();
  110. Label label = project.getAssignedLabel();
  111. if (label == null) { // project has no label -> so register
  112. // "build:projectName" on all non exclusive nodes
  113. if (node.getMode() != Mode.EXCLUSIVE) {
  114. String jobFunctionName = "build:" + projectName;
  115. newFunctionMap.put(jobFunctionName, new CustomGearmanFunctionFactory(
  116. jobFunctionName, StartJobWorker.class.getName(),
  117. project, computer, this.masterName, worker));
  118. }
  119. } else { // register "build:$projectName:$label" if this
  120. // node matches a node from the project label
  121. Set<Node> projectLabelNodes = label.getNodes();
  122. Set<LabelAtom> projectLabelAtoms = label.listAtoms();
  123. Set<LabelAtom> nodeLabelAtoms = node.getAssignedLabels();
  124. // Get the intersection of label atoms for the project and the current node
  125. Set<LabelAtom> nodeProjectLabelAtoms = new HashSet<LabelAtom>(projectLabelAtoms);
  126. nodeProjectLabelAtoms.retainAll(nodeLabelAtoms);
  127. // Register functions iff the current node is in
  128. // the list of nodes for the project's label
  129. if (projectLabelNodes.contains(node)) {
  130. String jobFunctionName = "build:" + projectName;
  131. // register without label (i.e. "build:$projectName")
  132. newFunctionMap.put(jobFunctionName, new CustomGearmanFunctionFactory(
  133. jobFunctionName, StartJobWorker.class.getName(),
  134. project, computer, this.masterName, worker));
  135. // iterate over the intersection of project and node labels
  136. for (LabelAtom labelAtom : nodeProjectLabelAtoms) {
  137. jobFunctionName = "build:" + projectName
  138. + ":" + labelAtom.getDisplayName();
  139. // register with label (i.e. "build:$projectName:$label")
  140. newFunctionMap.put(jobFunctionName, new CustomGearmanFunctionFactory(
  141. jobFunctionName, StartJobWorker.class.getName(),
  142. project, computer, this.masterName, worker));
  143. }
  144. }
  145. }
  146. }
  147. }
  148. if (!newFunctionMap.keySet().equals(functionMap.keySet())) {
  149. functionMap = newFunctionMap;
  150. Set<GearmanFunctionFactory> functionSet = new HashSet<GearmanFunctionFactory>(functionMap.values());
  151. updateJobs(functionSet);
  152. }
  153. }
  154. public synchronized Computer getComputer() {
  155. return computer;
  156. }
  157. }