brigadir
brigadir

Reputation: 6942

Check if Jenkins node is online for the job, otherwise send email alert

Having the Jenkins job dedicated to special node I'd like to have a notification if the job can't be run because the node is offline. Is it possible to set up this functionality?

In other words, the default Jenkins behavior is waiting for the node if the job has been started when the node is offline ('pending' job status). I want to fail (or don't start at all) the job in this case and send 'node offline' mail.

This node checking stuff should be inside the job because the job is executed rarely and I don't care if the node is offline when it's not needed for the job. I've tried external node watching plugin, but it doesn't do exactly what I want - it triggers emails every time the node goes offline and it's redundant in my case.

Upvotes: 2

Views: 14109

Answers (4)

Alexander Samoylov
Alexander Samoylov

Reputation: 2548

offlineNodes = 0
def isNodeOnline(nodeName) {
    def node = jenkins.model.Jenkins.instance.getNode(nodeName)
    return ((node != null) && node.getComputer().isOnline())
}

def runOnNode(nodeName) {
    stage(nodeName) {
        if (isNodeOnline(nodeName)) {
            node(nodeName) {
                echo("Do the stuff..")
            }
        } else {
            unstable ('Node ' + nodeName + ' is offline.');
            offlineNodes = 1
        }
    }
}

// main
try {
    runOnNode('yournode')
} catch (e) {
    print('Got exception: ' + e)
    currentBuild.result = 'FAILURE'
} finally {
    if (offlineNodes > 0) {
        currentBuild.result = 'ABORTED' // or UNSTABLE or whatever you like
        emailext(
            to: '[email protected]', replyTo: '$DEFAULT_REPLYTO', body: '''$DEFAULT_CONTENT''',
            subject: '${PROJECT_NAME} - Build ${BUILD_NUMBER} (' + currentBuild.currentResult + ')'
        )
    }
}

Upvotes: 0

dengmingcong
dengmingcong

Reputation: 11

Try to use the tool nodesByLabel of plugin Pipeline Utility Steps:

online_nodes = nodesByLabel label: "jenkins-slave-3", offline: false
if (online_nodes) {
    echo "online"
} else {
    echo "offline"
}

result (online):

 Started by user testteam
 Replayed #9
 [Pipeline] Start of Pipeline
 [Pipeline] nodesByLabel (hide)
 Found a total of 1 nodes with the 'jenkins-slave-3' label
 [Pipeline] echo
 online
 [Pipeline] End of Pipeline
 Finished: SUCCESS

result (offline):

 Started by user testteam
 Replayed #8
 [Pipeline] Start of Pipeline
 [Pipeline] nodesByLabel
 Could not find any nodes with 'jenkins-slave-1' label
 [Pipeline] echo
 offline
 [Pipeline] End of Pipeline
 Finished: SUCCESS

Upvotes: 0

MirrorBoy
MirrorBoy

Reputation: 869

I found an answer here. You can add a command-line or PowerShell block which invokes the curl command and processes a result

curl --silent $JENKINS_URL/computer/$JENKINS_NODENAME/api/json

The result json contains offline property with true/false value

Upvotes: 3

elworthy
elworthy

Reputation: 464

I don't think checking if the node is available can be done inside the job (e.g JobX) you want to run. The act of checking, specifically for your JobX at time of execution, will itself need a job to run - I don't know of a plugin/configuration option that'll do this. JobX can't check if the node is free for JobX.

I use a lot of flow jobs (in process of converting to pipeline logic) where JobA will trigger the JobB, thus JobA could run on master check the node for JobB, JobX in your case, triggering it if up.

JobA would need to be a freestyle job and run a 'execute system groovy script > Groovy command' build step. The groovy code below is pulled together from a number of working examples, so untested:

import hudson.model.*;
import hudson.AbortException;
import java.util.concurrent.CancellationException;


def allNodes = jenkins.model.Jenkins.instance.nodes
def triggerJob = false
for (node in allNodes) {
  if ( node.getComputer().isOnline() && node.nodeName == "special_node" ) {
    println node.nodeName + " " + node.getComputer().countBusy() + " " + node.getComputer().getOneOffExecutors().size
    triggerJob = true
    break
  }
}

if (triggerJob) {
    println("triggering child build as node available")
    def job = Hudson.instance.getJob('JobB')
    def anotherBuild
    try {
        def params = [
          new StringParameterValue('ParamOne', '123'),
        ]
        def future = job.scheduleBuild2(0, new Cause.UpstreamCause(build), new ParametersAction(params))
        anotherBuild = future.get()
    } catch (CancellationException x) {
        throw new AbortException("${job.fullDisplayName} aborted.")
    }

} else {    
    println("failing parent build as node not available")
    build.getExecutor().interrupt(hudson.model.Result.FAILURE)
    throw new InterruptedException()
}

To get the node offline email, you could just trigger a post build action to send emails on failure.

Upvotes: 1

Related Questions