[JIRA] (JENKINS-59778) Pipeline script fails to call Java code on slave: Failed to deserialize the Callable object

29 views
Skip to first unread message

alexander.samoylov@gmail.com (JIRA)

unread,
Oct 14, 2019, 7:57:03 AM10/14/19
to jenkinsc...@googlegroups.com
Alexander Samoylov created an issue
 
Jenkins / Bug JENKINS-59778
Pipeline script fails to call Java code on slave: Failed to deserialize the Callable object
Issue Type: Bug Bug
Assignee: Jeff Thompson
Components: pipeline, remoting
Created: 2019-10-14 11:56
Environment: Jenkins server: 2.190.1
Priority: Minor Minor
Reporter: Alexander Samoylov

This is a simple pipeline script on which the issue is reproduced:

import jenkins.security.MasterToSlaveCallable;
//import hudson.remoting.Callable;

def executeJavaCodeOnNode() {

    def node = Jenkins.getInstance().slaves.find({it.name == env.NODE_NAME})
    def hostChannel = node.getComputer().getChannel()
    def task = new MasterToSlaveCallable<String, IOException>() {
            public String call() throws IOException {
                return new String("-on the node-");
            }
    };
        
    hostChannel.call(task);
}

// Main
node ('linux-01') {
    executeJavaCodeOnNode()
}

This simple pipeline script fails with multiple Java exceptions. I think the most relevent of them are:

java.lang.IllegalArgumentException: Unable to locate class file for class WorkflowScript$1
	at hudson.remoting.Which.classFileUrl(Which.java:65)
	at hudson.remoting.RemoteClassLoader$ClassLoaderProxy.fetch4(RemoteClassLoader.java:860)
	at hudson.remoting.RemoteClassLoader$ClassLoaderProxy.fetch3(RemoteClassLoader.java:889)
	at sun.reflect.GeneratedMethodAccessor753.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at hudson.remoting.RemoteInvocationHandler$RPCRequest.perform(RemoteInvocationHandler.java:929)
	at hudson.remoting.Request$2.run(Request.java:369)
	at hudson.remoting.InterceptingExecutorService$1.call(InterceptingExecutorService.java:72)
	at org.jenkinsci.remoting.CallableDecorator.call(CallableDecorator.java:19)
	at hudson.remoting.CallableDecoratorList$1.call(CallableDecoratorList.java:21)
	at jenkins.util.ContextResettingExecutorService$2.call(ContextResettingExecutorService.java:46)
	at jenkins.security.ImpersonatingExecutorService$2.call(ImpersonatingExecutorService.java:71)

and

Also:   hudson.remoting.Channel$CallSiteStackTrace: Remote call to channel
		at hudson.remoting.Channel.attachCallSiteStackTrace(Channel.java:1743)
		at hudson.remoting.Request.call(Request.java:202)
		at hudson.remoting.RemoteInvocationHandler.invoke(RemoteInvocationHandler.java:286)
		at com.sun.proxy.$Proxy5.fetch3(Unknown Source)
		at hudson.remoting.RemoteClassLoader.findClass(RemoteClassLoader.java:209)
		at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
		at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
		at java.lang.Class.forName0(Native Method)
		at java.lang.Class.forName(Class.java:348)
		at hudson.remoting.MultiClassLoaderSerializer$Input.resolveClass(MultiClassLoaderSerializer.java:134)
		at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1868)
		at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1751)
		at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2042)
		at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1573)
		at java.io.ObjectInputStream.readObject(ObjectInputStream.java:431)
		at hudson.remoting.UserRequest.deserialize(UserRequest.java:291)
		at hudson.remoting.UserRequest.perform(UserRequest.java:190)
		at hudson.remoting.UserRequest.perform(UserRequest.java:54)
		at hudson.remoting.Request$2.run(Request.java:369)
		at hudson.remoting.InterceptingExecutorService$1.call(InterceptingExecutorService.java:72)
....
....
....
Caused: java.lang.Error: Failed to deserialize the Callable object.
	at hudson.remoting.UserRequest.perform(UserRequest.java:196)
	at hudson.remoting.UserRequest.perform(UserRequest.java:54)
	at hudson.remoting.Request$2.run(Request.java:369)
	at hudson.remoting.InterceptingExecutorService$1.call(InterceptingExecutorService.java:72)

I thought that this issue is connected to serialization and tried to add @NonCPS to my method, but it did not help.

Add Comment Add Comment
 
This message was sent by Atlassian Jira (v7.13.6#713006-sha1:cc4451f)
Atlassian logo

dbeck@cloudbees.com (JIRA)

unread,
Oct 15, 2019, 4:56:03 AM10/15/19
to jenkinsc...@googlegroups.com
Daniel Beck commented on Bug JENKINS-59778
 
Re: Pipeline script fails to call Java code on slave: Failed to deserialize the Callable object

I'm pretty sure writing callables in pipeline is unsupported.

Devin Nusbaum perhaps? Does this look sane?

dnusbaum@cloudbees.com (JIRA)

unread,
Oct 15, 2019, 9:28:02 AM10/15/19
to jenkinsc...@googlegroups.com

Yes, using remoting directly from Pipelines is not supported. The supported way to do this from Pipeline is to implement Step in a plugin, and have the step handle the interactions with remoting. Alexander Samoylov, this has never worked for you, right? Or did it work previously before some plugin/core upgrade?

alexander.samoylov@gmail.com (JIRA)

unread,
Oct 15, 2019, 9:54:03 AM10/15/19
to jenkinsc...@googlegroups.com

Devin Nusbaum, Yes, it never worked for me. I will try to describe my use case better.
I ran some Java code on slave for debugging purposes. I used the class GroovyInstallation in my pipeline script and the problem was the getExecutable(VirtualChannel channel) method of this class returned null (even after the successful installation).
The method getExecutable(VirtualChannel channel) does almost the same what I wrote in my example above (see https://github.com/jenkinsci/groovy-plugin/blob/master/src/main/java/hudson/plugins/groovy/GroovyInstallation.java), that is uses Callable. I wanted to do the same directly from the pipeline code in order to run my modified version of getExecutable (with printouts etc.), but as you see it failed with those exceptions.

Obviously I had a question, why Callable usage this works via the instance of GroovyInstallation, but does not work from the pipeline directly. I didn't understand what is actually the difference and that's why opened this ticket. If you think that this is not supported, why then it works fine via the instance of GroovyInstallation?

alexander.samoylov@gmail.com (JIRA)

unread,
Oct 15, 2019, 9:56:03 AM10/15/19
to jenkinsc...@googlegroups.com
Alexander Samoylov edited a comment on Bug JENKINS-59778
[~dnusbaum], Yes, it never worked for me. I will try to describe my use case better.

I ran some Java code on slave for debugging purposes. I used the class GroovyInstallation in my pipeline script and the problem was the getExecutable(VirtualChannel channel) method of this class returned null (even after the successful installation).
The method getExecutable(VirtualChannel channel) does almost the same what I wrote in my example above (see https://github.com/jenkinsci/groovy-plugin/blob/master/src/main/java/hudson/plugins/groovy/GroovyInstallation.java), that is uses Callable. I wanted to do the same directly from the pipeline code in order to run my modified version of getExecutable (with printouts etc.), but as you see it failed with those exceptions.

Obviously I had a question, why Callable usage
this works via the instance of GroovyInstallation, but does not work from the pipeline directly. I didn't understand what is actually the difference and that's why opened this ticket. If you think that this is not supported, why then it works fine via the instance of GroovyInstallation?

dnusbaum@cloudbees.com (JIRA)

unread,
Oct 15, 2019, 10:08:03 AM10/15/19
to jenkinsc...@googlegroups.com

Alexander Samoylov GroovyInstallation is Java code from a plugin. Compared to Groovy code in Pipeline, the most important differences are that it is not CPS-transformed, it is not sandbox-transformed, its class loader hierarchy is different, and there is a class file on disk for it somewhere instead of whatever happens for Groovy code run by the embedded Groovy interpreter. I suspect the latter is what is causing problems in your case. Both Pipeline Groovy code and remoting do some tricky low-level things, and so they don't play well together.

If you just want to run some Groovy code for debugging purposes, you could try using the script console, which will at least eliminate the Pipeline-specific complexities, to see if that makes a difference.

dnusbaum@cloudbees.com (JIRA)

unread,
Oct 15, 2019, 10:09:03 AM10/15/19
to jenkinsc...@googlegroups.com

alexander.samoylov@gmail.com (JIRA)

unread,
Oct 16, 2019, 12:41:01 PM10/16/19
to jenkinsc...@googlegroups.com
Alexander Samoylov commented on Bug JENKINS-59778
 
Re: Pipeline script fails to call Java code on slave: Failed to deserialize the Callable object

Well, I understand. Thank you for the clarification.
You wrote also above that "The supported way to do this from Pipeline is to implement Step in a plugin, and have the step handle the interactions with remoting". Probably you know some pipeline code which implements similar thing? I tried to look for on https://github.com/jenkinsci/jenkins-scripts/tree/master/scriptler, but did not find anything useful. Could you please refer to some code snippet, of course if you know such one?

Reply all
Reply to author
Forward
0 new messages