Update zuul-gearman protocol.
* Use name+number as the build identifier for all meta-jobs. (Zuul has name + number as build metadata, so avoid adding new/duplicate features). * Refer to the name of the manager worker as 'manager' instead of 'master' to avoid jenkins specifics. * Just call the url "url" instead of "full_url". * Change SetDescriptionWorker to use name+number as the build id. Also, expect 'html_description' instead of 'description'. * Don't catch as many exceptions, instead, let them propogate so that they get turned into WORK_EXCEPTION packets with information (instead of WORK_FAIL packets which have no info). * Change StopJobWorker to use the same name+number interface as setDescriptionWorker (for consistency, expandability, plus it makes the code simpler). Change-Id: I8e078540c252bf9c1f14b79f8182517cbaa13555
This commit is contained in:
parent
78abc3d903
commit
7a8d940c4b
|
@ -18,8 +18,12 @@
|
|||
|
||||
package hudson.plugins.gearman;
|
||||
|
||||
import hudson.model.AbstractProject;
|
||||
import hudson.model.Computer;
|
||||
import hudson.model.Node;
|
||||
import hudson.model.Run;
|
||||
|
||||
import jenkins.model.Jenkins;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -55,4 +59,25 @@ public class GearmanPluginUtil {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to finds the build with the unique build id.
|
||||
*
|
||||
* @param jobName
|
||||
* The jenkins job or project name
|
||||
* @param buildNumber
|
||||
* The jenkins build number
|
||||
* @return
|
||||
* the build Run if found, otherwise return null
|
||||
*/
|
||||
public static Run<?,?> findBuild(String jobName, int buildNumber) {
|
||||
|
||||
AbstractProject<?,?> project = Jenkins.getInstance().getItemByFullName(jobName, AbstractProject.class);
|
||||
if (project != null){
|
||||
Run<?,?> run = project.getBuildByNumber(buildNumber);
|
||||
if (run != null) {
|
||||
return run;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,15 +19,12 @@
|
|||
|
||||
package hudson.plugins.gearman;
|
||||
|
||||
import hudson.model.AbstractProject;
|
||||
import hudson.model.Run;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.Map;
|
||||
|
||||
import jenkins.model.Jenkins;
|
||||
|
||||
import org.gearman.client.GearmanJobResult;
|
||||
import org.gearman.client.GearmanJobResultImpl;
|
||||
import org.gearman.worker.AbstractGearmanFunction;
|
||||
|
@ -59,82 +56,49 @@ public class SetDescriptionWorker extends AbstractGearmanFunction {
|
|||
|
||||
// check job results
|
||||
boolean jobResult = false;
|
||||
String jobExceptionMsg = "";
|
||||
String jobWarningMsg = "";
|
||||
String jobResultMsg = "";
|
||||
|
||||
String decodedData;
|
||||
// decode json
|
||||
try {
|
||||
// decode json
|
||||
String decodedData = new String((byte[]) this.data, "UTF-8");
|
||||
// convert parameters passed in from client to hash map
|
||||
Gson gson = new Gson();
|
||||
Map<String, String> data = gson.fromJson(decodedData,
|
||||
new TypeToken<Map<String, String>>() {
|
||||
}.getType());
|
||||
|
||||
// get build description
|
||||
String buildDescription = data.get("description");
|
||||
// get build id
|
||||
String buildId = data.get("build_id");
|
||||
String[] idToken = buildId.split(":");
|
||||
if (idToken.length != 2 || buildDescription == null || buildId == null) {
|
||||
jobExceptionMsg = "Invalid Unique Id";
|
||||
throw new IllegalArgumentException(jobExceptionMsg);
|
||||
} else {
|
||||
String jobName = idToken[0];
|
||||
String jobId = idToken[1];
|
||||
if (!jobName.isEmpty() && !jobId.isEmpty()) {
|
||||
// find build then update its description
|
||||
Run<?,?> build = findBuild(jobName, jobId);
|
||||
if (build != null) {
|
||||
build.setDescription(buildDescription);
|
||||
jobResultMsg = "Description for Jenkins build " +buildId+" was pdated to " + buildDescription;
|
||||
jobResult = true;
|
||||
} else {
|
||||
jobExceptionMsg = "Cannot find build with id " + buildId;
|
||||
throw new IllegalArgumentException(jobExceptionMsg);
|
||||
}
|
||||
} else {
|
||||
jobExceptionMsg = "Build id is invalid or not specified";
|
||||
throw new IllegalArgumentException(jobExceptionMsg);
|
||||
}
|
||||
}
|
||||
decodedData = new String((byte[]) this.data, "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
jobExceptionMsg = "Error decoding parameters";
|
||||
} catch (NullPointerException e) {
|
||||
jobExceptionMsg = "Error decoding parameters";
|
||||
} catch (IOException e) {
|
||||
jobExceptionMsg = "Error setting build description";
|
||||
} catch (IllegalArgumentException e) {
|
||||
jobExceptionMsg = e.getMessage();
|
||||
throw new IllegalArgumentException("Unsupported encoding exception in argument");
|
||||
}
|
||||
|
||||
// convert parameters passed in from client to hash map
|
||||
Gson gson = new Gson();
|
||||
Map<String, String> data = gson.fromJson(decodedData,
|
||||
new TypeToken<Map<String, String>>() {
|
||||
}.getType());
|
||||
|
||||
// get build description
|
||||
String buildDescription = data.get("html_description");
|
||||
// get build id
|
||||
String jobName = data.get("name");
|
||||
String buildNumber = data.get("number");
|
||||
if (!jobName.isEmpty() && !buildNumber.isEmpty()) {
|
||||
// find build then update its description
|
||||
Run<?,?> build = GearmanPluginUtil.findBuild(jobName, Integer.parseInt(buildNumber));
|
||||
if (build != null) {
|
||||
try {
|
||||
build.setDescription(buildDescription);
|
||||
} catch (IOException e) {
|
||||
throw new IllegalArgumentException("Unable to set description for " +
|
||||
jobName + ": " + buildNumber);
|
||||
}
|
||||
jobResultMsg = "Description for Jenkins build " +buildNumber+" was updated to " + buildDescription;
|
||||
jobResult = true;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Cannot find build number " +
|
||||
buildNumber);
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("Build id is invalid or not specified");
|
||||
}
|
||||
|
||||
GearmanJobResult gjr = new GearmanJobResultImpl(this.jobHandle, jobResult,
|
||||
jobResultMsg.getBytes(), jobWarningMsg.getBytes(),
|
||||
jobExceptionMsg.getBytes(), 0, 0);
|
||||
jobResultMsg.getBytes(), null, null, 0, 0);
|
||||
return gjr;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function to finds the build with the unique build id.
|
||||
*
|
||||
* @param jobName
|
||||
* The jenkins job or project name
|
||||
* @param uuid
|
||||
* The jenkins job id
|
||||
* @return
|
||||
* the build Run if found, otherwise return null
|
||||
*/
|
||||
private Run<?,?> findBuild(String jobName, String jobId) {
|
||||
|
||||
AbstractProject<?,?> project = Jenkins.getInstance().getItemByFullName(jobName, AbstractProject.class);
|
||||
if (project != null){
|
||||
Run<?,?> run = project.getBuild(jobId);
|
||||
if (run != null) {
|
||||
return run;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -87,14 +87,11 @@ public class StartJobWorker extends AbstractGearmanFunction {
|
|||
|
||||
data.put("name", project.getName());
|
||||
data.put("number", build.getNumber());
|
||||
data.put("id", build.getId());
|
||||
data.put("build_id", project.getName()+":"+build.getId());
|
||||
data.put("url", build.getUrl());
|
||||
data.put("master", masterName);
|
||||
data.put("manager", masterName);
|
||||
|
||||
String rootUrl = Hudson.getInstance().getRootUrl();
|
||||
if (rootUrl != null) {
|
||||
data.put("full_url", rootUrl + build.getUrl());
|
||||
data.put("url", rootUrl + build.getUrl());
|
||||
}
|
||||
|
||||
Result result = build.getResult();
|
||||
|
|
|
@ -19,16 +19,11 @@
|
|||
|
||||
package hudson.plugins.gearman;
|
||||
|
||||
import hudson.model.AbstractBuild;
|
||||
import hudson.model.Computer;
|
||||
import hudson.model.Run;
|
||||
import hudson.model.Executor;
|
||||
import hudson.model.Node;
|
||||
import hudson.model.Queue;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.List;
|
||||
|
||||
import jenkins.model.Jenkins;
|
||||
import java.util.Map;
|
||||
|
||||
import org.gearman.client.GearmanJobResult;
|
||||
import org.gearman.client.GearmanJobResultImpl;
|
||||
|
@ -36,6 +31,9 @@ import org.gearman.worker.AbstractGearmanFunction;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
/**
|
||||
* This is a gearman function that will cancel/abort jenkins builds
|
||||
*
|
||||
|
@ -53,137 +51,54 @@ public class StopJobWorker extends AbstractGearmanFunction {
|
|||
*/
|
||||
@Override
|
||||
public GearmanJobResult executeFunction() {
|
||||
String cancelID = null;
|
||||
if (this.data != null) {
|
||||
// decode the data from the client
|
||||
try {
|
||||
cancelID = new String((byte[]) this.data, "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
// check build and pass results back to client
|
||||
boolean jobResult = true;
|
||||
String jobFailureMsg = "";
|
||||
String jobWarningMsg = "";
|
||||
// check job results
|
||||
boolean jobResult = false;
|
||||
String jobResultMsg = "";
|
||||
|
||||
if (cancelID == null || cancelID.isEmpty()) {
|
||||
logger.info("---- Client passed in an invalid UUID");
|
||||
jobFailureMsg = "I need the job Id please";
|
||||
jobResult = false;
|
||||
} else {
|
||||
String decodedData;
|
||||
// decode json
|
||||
try {
|
||||
decodedData = new String((byte[]) this.data, "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new IllegalArgumentException("Unsupported encoding exception in argument");
|
||||
}
|
||||
// convert parameters passed in from client to hash map
|
||||
Gson gson = new Gson();
|
||||
Map<String, String> data = gson.fromJson(decodedData,
|
||||
new TypeToken<Map<String, String>>() {
|
||||
}.getType());
|
||||
|
||||
// Abort running jenkins build that contain matching uuid
|
||||
jobResult = abortBuild(cancelID);
|
||||
// get build id
|
||||
String jobName = data.get("name");
|
||||
String buildNumber = data.get("number");
|
||||
if (jobName.isEmpty() || buildNumber.isEmpty()) {
|
||||
throw new IllegalArgumentException("Build id is invalid or not specified");
|
||||
}
|
||||
|
||||
if (jobResult){
|
||||
jobResultMsg = "Canceled jenkins build " + cancelID;
|
||||
// Abort running jenkins build that contain matching uuid
|
||||
Run<?,?> build = GearmanPluginUtil.findBuild(jobName, Integer.parseInt(buildNumber));
|
||||
if (build != null) {
|
||||
if (build.isBuilding()) {
|
||||
Executor executor = build.getExecutor();
|
||||
// abort the running jenkins build
|
||||
if (!executor.isInterrupted()) {
|
||||
executor.interrupt();
|
||||
logger.info("---- Aborting build : " +
|
||||
jobName + ": " + buildNumber);
|
||||
jobResult = true;
|
||||
}
|
||||
} else {
|
||||
jobFailureMsg = "Could not cancel build " + cancelID;
|
||||
jobResult = false;
|
||||
logger.info("---- Request to abourt non-building build : " +
|
||||
jobName + ": " + buildNumber);
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("Cannot find build " +
|
||||
jobName + ": " + buildNumber);
|
||||
}
|
||||
|
||||
GearmanJobResult gjr = new GearmanJobResultImpl(this.jobHandle, jobResult,
|
||||
jobResultMsg.getBytes(), jobWarningMsg.getBytes(),
|
||||
jobFailureMsg.getBytes(), 0, 0);
|
||||
jobResultMsg.getBytes(), null, null, 0, 0);
|
||||
return gjr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to abort a currently running Jenkins build
|
||||
* Running Jenkins builds are builds that actively being
|
||||
* executed by Jenkins
|
||||
*
|
||||
* @param uuid
|
||||
* The build UUID
|
||||
* @return
|
||||
* true if build was aborted, otherwise false
|
||||
*/
|
||||
private boolean abortBuild (String uuid) {
|
||||
|
||||
/*
|
||||
* iterate over the executors on master and slave nodes to find the
|
||||
* build on the executor with the matching uuid
|
||||
*/
|
||||
// look at executors on master
|
||||
Node masterNode = Computer.currentComputer().getNode();
|
||||
Computer masterComp = masterNode.toComputer();
|
||||
if (!masterComp.isIdle()) { // ignore idle master
|
||||
List<Executor> masterExecutors = masterComp.getExecutors();
|
||||
for (Executor executor: masterExecutors) {
|
||||
|
||||
if (executor.isIdle()) { // ignore idle executors
|
||||
continue;
|
||||
}
|
||||
|
||||
// lookup the running build with matching uuid
|
||||
Queue.Executable executable = executor.getCurrentExecutable();
|
||||
AbstractBuild<?, ?> currBuild = (AbstractBuild) executable;
|
||||
int buildNum = currBuild.getNumber();
|
||||
String buildId = currBuild.getId();
|
||||
String runNodeName = currBuild.getBuiltOn().getNodeName();
|
||||
NodeParametersAction param = currBuild.getAction(NodeParametersAction.class);
|
||||
String buildParams = param.getParameters().toString();
|
||||
|
||||
if (param.getUuid().equals(uuid)) {
|
||||
|
||||
logger.info("---- Aborting build : "+buildNum+": "+buildId+" on " + runNodeName
|
||||
+" with UUID " + uuid + " and build params " + buildParams);
|
||||
|
||||
// abort the running jenkins build
|
||||
if (!executor.isInterrupted()) {
|
||||
executor.interrupt();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// look at executors on slave nodes
|
||||
List<Node> nodes = Jenkins.getInstance().getNodes();
|
||||
if (nodes.isEmpty()) { //NOOP
|
||||
return false;
|
||||
}
|
||||
|
||||
for (Node node: nodes){
|
||||
|
||||
Computer slave = node.toComputer();
|
||||
if (slave.isIdle()) { // ignore all idle slaves
|
||||
continue;
|
||||
}
|
||||
|
||||
List<Executor> executors = slave.getExecutors();
|
||||
for (Executor executor: executors) {
|
||||
|
||||
if (executor.isIdle()) { // ignore idle executors
|
||||
continue;
|
||||
}
|
||||
|
||||
// lookup the running build with matching uuid
|
||||
Queue.Executable executable = executor.getCurrentExecutable();
|
||||
AbstractBuild<?, ?> currBuild = (AbstractBuild) executable;
|
||||
int buildNum = currBuild.getNumber();
|
||||
String buildId = currBuild.getId();
|
||||
String runNodeName = currBuild.getBuiltOn().getNodeName();
|
||||
NodeParametersAction param = currBuild.getAction(NodeParametersAction.class);
|
||||
String buildParams = param.getParameters().toString();
|
||||
|
||||
if (param.getUuid().equals(uuid)) {
|
||||
|
||||
logger.info("---- Aborting build : "+buildNum+": "+buildId+" on " + runNodeName
|
||||
+" with UUID " + uuid + " and build params " + buildParams);
|
||||
|
||||
// abort the running jenkins build
|
||||
if (!executor.isInterrupted()) {
|
||||
executor.interrupt();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue