How can I isolate the Jenkins Groovy shared library classloader pipeline?

I have a Groovy library, available as a global shared library:

package com.example @Grab(group="org.apache.httpcomponents", module="httpclient", version="[4.5.3,)") import org.apache.http.HttpHost import org.apache.http.impl.client.HttpClients class MyClass implements Serializable { static def run() { return HttpClients.custom() .setProxy(new HttpHost("proxy.example.com", 3128)) .build() } static def debug() { return (""" this: ${this.classLoader.class.toString()} ${this.classLoader.hashCode().toString()} HttpHost: ${HttpHost.class.classLoader.class.toString()} ${HttpHost.class.classLoader.hashCode()} HttpClients: ${HttpClients.class.classLoader.class.toString()} ${HttpClients.class.classLoader.hashCode()} """) } } 

And working with a Jenkins script using this library:

 @Library('example') _ node { echo "${com.example.MyClass.debug()}" com.example.MyClass.run() } 

When the task runs, I get the following output from debug() , followed by an error from run() :

  this: class org.jenkinsci.plugins.workflow.cps.CpsGroovyShell$CleanGroovyClassLoader 765101363 HttpHost: class hudson.ClassicPluginStrategy$AntClassLoader2 804623541 HttpClients: class hudson.ClassicPluginStrategy$AntClassLoader2 1870591909 hudson.remoting.ProxyException: groovy.lang.MissingMethodException: No signature of method: org.apache.http.impl.client.HttpClientBuilder.setProxy() is applicable for argument types: (org.apache.http.HttpHost) values: [http://proxy.example.com:3128] Possible solutions: setProxy(org.apache.http.HttpHost) The following classes appear as argument class and as parameter class, but are defined by different class loader 

It’s clear to me that some Jenkins plugins already have httpcomponents dependency, and looks like this:

  • My @Grab annotation made it load the requested version of httpclient (as mentioned in ~/.groovy/grapes ).
  • But this version is not downloaded or used by the Groovy library, but some other version that is dependent on some Jenkins plugin.
  • And even more annoyingly, HttpHost and HttpClients are loaded from different class loaders, so I can't even use the version of the plugin that leaked into my Groovy class loader.

Version

  • Jenkins: 2.20

Plugin versions

  • Groovy: 2.0
  • Pipeline: 2.5
  • Pipeline: Groovy: 2.30
  • Pipeline: Shared Groovy Libraries: 2.8

Is there a way to run my Groovy in a class loader that is isolated from the Jenkins plugin? How do Jenkins and Groovy common library code organize class loaders? Is this a leak of classes imposed by plugins intentionally?

Is this a mistake or am I doing something wrong? I understand that I have several versions on Jenkins, so one thing to try.

As in the case, the system is unusable if I’m not lucky that I have dependencies that another plug-in does not have, or fortunate that they are compatible with any version that the class loader detects.

+7
classloader jenkins groovy jenkins-pipeline
source share
1 answer

@Grab does not work when libraries are bound to folders. Using @Grab in a library only works when the library is configured in global settings. This is intentional and not a mistake with Jenkins in accordance with the plugin structure documentation .

The documentation further states:

If you want your own libraries to be loaded in front of you (for example, you want to get a newer version of the speed or another library), you can configure your plugin to use a different classloader strategy by specifying the hpi plugin in your pom.xml

Personally, I would upgrade Jenkins (and Pipelines) to the latest version available before trying the above.

0
source share

All Articles