espenalb
espenalb

Reputation: 548

How to take a Jenkins node offline in a pipeline script

We want to verify that the Jenkins node is healthy before starting time-consuming integration tests. If the node is not healthy, we want to take it offline so that someone can connect and fix it.

Upvotes: 2

Views: 3376

Answers (1)

espenalb
espenalb

Reputation: 548

After quite a bit of trial-and-error, I ended up with this solution:

def ExecuteTestsOnSelectedNode() {
     stage("integrationtests") {
         testSystemVerified = false
         while(!testSystemVerified) { // Retry if test system verification failed -  hopefully another node can execute this test...    
             node("nodelabel") {
                 // ... code for unstashing test assemblies omitted
                 try {
                     testSystemVerified = checkTestSystem(info, testSetup, testAssemblies);
                 }
                 catch (Exception e) {
                     echo "!!!!!!!!!!!!!!!!!! Test system verification failed !!!!!!!!!!!!!!!!!!!!!!!!\n" + e
                     throw e
                 }
                 if (testSystemVerified) {
                     // Then it is safe to execute the actual tests
                 }                  
             }
         }
     }
}

def checkTestSystem(info, testSetup, testAssemblies) {
    try {            
        // Execute some command that (quickly) verifies the health of the node
        bat "$info.test_runner $test_args"
        return true // If we get here the test system is OK
    }
    catch (hudson.AbortException e) {
        message = "!!!!!!!!!!!!!!!!!! Test system verification aborted !!!!!!!!!!!!!!!!!!!!!!!!\n" + e
        echo message
        throw e
    }
    catch (Exception e) {
        message = "!!!!!!!!!!!!!!!!!! Test system verification failed !!!!!!!!!!!!!!!!!!!!!!!!\n" + e
        echo message
        markNodeOffline(message)
        return false
    }
}

@NonCPS
def markNodeOffline(message) {
    node = getCurrentNode(env.NODE_NAME)
    computer = node.toComputer()
    computer.setTemporarilyOffline(true)
    computer.doChangeOfflineCause(message)
    computer = null
    node = null
}

@NonCPS
def getCurrentNode(nodeName) {
  for (node in Jenkins.instance.nodes) {
      if (node.getNodeName() == nodeName) {
        echo "Found node for $nodeName"
        return node
    }
  }
  throw new Exception("No node for $nodeName")
}

Upvotes: 5

Related Questions