Jenkins slave disconnect via pipeline script from scm

2,107 views
Skip to first unread message

Martins Gulbis

unread,
Mar 3, 2017, 2:00:56 AM3/3/17
to Jenkins Developers
Hi,

I'm struggling with jenkins slave disconnect from pipeline stage which is being executed on master. After a bit of googling I got following solution which works when executed as "Pipeline script"


import hudson.model.Slave.*
import hudson.slaves.OfflineCause.SimpleOfflineCause;

class OfflineMessage extends org.jvnet.localizer.Localizable {
def message;
OfflineMessage(String msg) {
super(null, null, []);
def time = new Date(); //.format("HH:mm MM/dd/yy z",TimeZone.getTimeZone("EST"))
this.message = msg; //"Toggling the node offline:" + time
}
String toString() {
this.message;
}
String toString(java.util.Locale l) {
toString();
}
}

def NodeDisconnect (NodeName) {
    def WorkNode = jenkins.model.Jenkins.instance.getNode(NodeName)
    if (WorkNode) {
        println ("GOT NODE")
        def WorkComputer = WorkNode.computer
        def WorkLouncher = WorkComputer.getLauncher();
        def WorkListener = TaskListener.NULL
        if (WorkComputer.isOnline()){
            println("Node is online")
            if (WorkComputer.isIdle()){
                println ("Current node status Online, Idle with ${WorkComputer.countExecutors()}:${WorkComputer.countBusy()} executors")
                println ("About to disconnect node")
                WorkLouncher.beforeDisconnect(WorkComputer,WorkListener)
                WorkComputer.disconnect(SimpleOfflineCause.create(new OfflineMessage("Disconnected for VirtualBox snapshot restore")));
                WorkLouncher.afterDisconnect(WorkComputer,WorkListener)
                println ("Wait for node to go offline")
                WorkComputer.waitUntilOffline()
            }
            else {
                println ("Current node status Online, Busy with ${WorkComputer.countExecutors()}:${WorkComputer.countBusy()} executors")
                //raise
            }
        }
        else {
            println("Node is offline with cause:${WorkComputer.getOfflineCauseReason()}")
            //raise
        }
    }
    else {
        println ("NODE NOT FOUND")
        //raise error 
    }
}

node('master') {
    stage('Stage1'){
        NodeDisconnect('Node1')
        sleep 3
        NodeConnect('Node1')
        sleep 3
    }
}
node('Node1'){
    stage('Stage2'){
        echo "HI FROM NODE"
    }
}

But when I try to execute it as "Pipeline script from SCM" it fails with 
...
org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: unclassified staticMethod hudson.slaves.OfflineCause$SimpleOfflineCause create OfflineMessage at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SandboxInterceptor.onStaticCall(SandboxInterceptor.java:138) at org.kohsuke.groovy.sandbox.impl.Checker$2.call(Checker.java:180) at org.kohsuke.groovy.sandbox.impl.Checker.checkedStaticCall(Checker.java:177) at org.kohsuke.groovy.sandbox.impl.Checker.checkedCall(Checker.java:91) at com.cloudbees.groovy.cps.sandbox.SandboxInvoker.methodCall(SandboxInvoker.java:16) at Script2.NodeDisconnect(Script2.groovy:42) at WorkflowScript.run(WorkflowScript:10) at ___cps.transform___(Native Method) at com.cloudbees.groovy.cps.impl.ContinuationGroup.methodCall(ContinuationGroup.java:57) at com.cloudbees.groovy.cps.impl.FunctionCallBlock$ContinuationImpl.dispatchOrArg(FunctionCallBlock.java:109) at com.cloudbees.groovy.cps.impl.FunctionCallBlock$ContinuationImpl.fixArg(FunctionCallBlock.java:82) at sun.reflect.GeneratedMethodAccessor702.invoke(Unknown Source)
...


Can somebody give a hint or example on how to rewrite OfflineMessage class to get a round exception which is being rised by GroovyCallSiteSelector.staticMethod(receiver, method, args);

PS. I'm new to Jenkins, Groovy and java so please keep answers as simple as possible ...

Martins Gulbis

unread,
Mar 3, 2017, 2:03:00 AM3/3/17
to Jenkins Developers

Martins Gulbis

unread,
Mar 3, 2017, 5:17:09 AM3/3/17
to Jenkins Developers
For those who stumble upon this problem I got around it by using OfflineCause.UserCause instad of OfflineCause.SimpleOfflineCause. For me it looks like this 

def NodeDisconnect (NodeName) {
    println("Node Disconnect")
    def WorkNode = jenkins.model.Jenkins.instance.getNode(NodeName)
    if (WorkNode) {
        println ("GOT NODE")
        def WorkComputer = WorkNode.computer
        def WorkLouncher = WorkComputer.getLauncher();
        def WorkListener = TaskListener.NULL
        if (WorkComputer.isOnline()){
            println("Node is online")
            if (WorkComputer.isIdle()){
                println ("Current node status Online, Idle with ${WorkComputer.countExecutors()}:${WorkComputer.countBusy()} executors")
                println ("About to disconnect node")
                def WorkOfflineCause = new OfflineCause.UserCause(User.current(),'Disconnected for VirtualBox snapshot restore...')
                WorkLouncher.beforeDisconnect(WorkComputer,WorkListener)
                WorkComputer.disconnect(WorkOfflineCause);
Reply all
Reply to author
Forward
0 new messages