Details
-
New Feature
-
Status: Resolved (View Workflow)
-
Major
-
Resolution: Fixed
-
None
Description
The workflow plugin and its groovy DSL should support the use of Grape and the @Grab attribute to allow the creation of workflows that depend on external libraries such as HTTP Builder or jYaml.
This issue seems closely related to JENKINS-18349 and other issues referenced in the comments of that issue.
Attachments
Issue Links
- depends on
-
JENKINS-18349 Allow to use @Grab in a Script Console
-
- Open
-
- is related to
-
JENKINS-26635 Provide Groovy workflow build step
-
- Resolved
-
-
JENKINS-42307 Please add general support for Grape (and ivy)
-
- Open
-
-
JENKINS-31155 Workflow shared library improvements
-
- Closed
-
- links to
(1 links to)
Activity
Field | Original Value | New Value |
---|---|---|
Link |
This issue is related to |
Resolution | Won't Do [ 10001 ] | |
Status | Open [ 1 ] | Resolved [ 5 ] |
Link |
This issue is related to |
Workflow | JNJira [ 160183 ] | JNJira + In-Review [ 196355 ] |
Resolution | Won't Do [ 10001 ] | |
Status | Resolved [ 5 ] | Reopened [ 4 ] |
Status | Reopened [ 4 ] | Open [ 1 ] |
Status | Open [ 1 ] | In Progress [ 3 ] |
Remote Link | This issue links to "workflow-cps-global-lib PR 9 (Web Link)" [ 14712 ] |
Status | In Progress [ 3 ] | In Review [ 10005 ] |
Link | This issue is related to SECURITY-336 [ SECURITY-336 ] |
Comment |
[ If I install the [Ivy Plugin|https://wiki.jenkins-ci.org/display/JENKINS/Ivy+Plugin] I get a new (but similar) stacktrace: {code} java.lang.NoClassDefFoundError: org/apache/ivy/Ivy at java.lang.Class.getDeclaredMethods0(Native Method) at java.lang.Class.privateGetDeclaredMethods(Class.java:2701) at java.lang.Class.privateGetPublicMethods(Class.java:2902) at java.lang.Class.getMethods(Class.java:1615) at java.beans.Introspector.getPublicDeclaredMethods(Introspector.java:1336) at java.beans.Introspector.getTargetMethodInfo(Introspector.java:1197) at java.beans.Introspector.getBeanInfo(Introspector.java:426) at java.beans.Introspector.getBeanInfo(Introspector.java:173) at groovy.lang.MetaClassImpl$15.run(MetaClassImpl.java:3290) at java.security.AccessController.doPrivileged(Native Method) at groovy.lang.MetaClassImpl.addProperties(MetaClassImpl.java:3288) at groovy.lang.MetaClassImpl.initialize(MetaClassImpl.java:3265) at org.codehaus.groovy.reflection.ClassInfo.getMetaClassUnderLock(ClassInfo.java:254) at org.codehaus.groovy.reflection.ClassInfo.getMetaClass(ClassInfo.java:285) at groovy.grape.GrapeIvy.$getStaticMetaClass(GrapeIvy.groovy) at groovy.grape.GrapeIvy.<init>(GrapeIvy.groovy:81) at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) at java.lang.reflect.Constructor.newInstance(Constructor.java:423) at java.lang.Class.newInstance(Class.java:442) at groovy.grape.Grape.getInstance(Grape.java:121) at groovy.grape.Grape.grab(Grape.java:159) at groovy.grape.GrabAnnotationTransformation.visit(GrabAnnotationTransformation.java:378) at org.codehaus.groovy.transform.ASTTransformationVisitor$3.call(ASTTransformationVisitor.java:321) at org.codehaus.groovy.control.CompilationUnit.applyToSourceUnits(CompilationUnit.java:931) at org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:593) at org.codehaus.groovy.control.CompilationUnit.processPhaseOperations(CompilationUnit.java:569) at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:546) at groovy.lang.GroovyClassLoader.doParseClass(GroovyClassLoader.java:298) at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:268) at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:254) at groovy.lang.GroovyClassLoader.recompile(GroovyClassLoader.java:761) at groovy.lang.GroovyClassLoader.loadClass(GroovyClassLoader.java:718) at groovy.lang.GroovyClassLoader.loadClass(GroovyClassLoader.java:787) at java.lang.ClassLoader.loadClass(ClassLoader.java:411) at groovy.lang.GroovyClassLoader.loadClass(GroovyClassLoader.java:677) at groovy.lang.GroovyClassLoader.loadClass(GroovyClassLoader.java:545) at org.codehaus.groovy.control.ClassNodeResolver.tryAsLoaderClassOrScript(ClassNodeResolver.java:185) at org.codehaus.groovy.control.ClassNodeResolver.findClassNode(ClassNodeResolver.java:170) at org.codehaus.groovy.control.ClassNodeResolver.resolveName(ClassNodeResolver.java:126) at org.codehaus.groovy.control.ResolveVisitor.resolveToOuter(ResolveVisitor.java:676) at org.codehaus.groovy.control.ResolveVisitor.resolve(ResolveVisitor.java:308) at org.codehaus.groovy.control.ResolveVisitor.resolveFromModule(ResolveVisitor.java:638) at org.codehaus.groovy.control.ResolveVisitor.resolve(ResolveVisitor.java:308) at org.codehaus.groovy.control.ResolveVisitor.resolve(ResolveVisitor.java:276) at org.codehaus.groovy.control.ResolveVisitor.resolveOrFail(ResolveVisitor.java:260) at org.codehaus.groovy.control.ResolveVisitor.resolveOrFail(ResolveVisitor.java:272) at org.codehaus.groovy.control.ResolveVisitor.transformConstructorCallExpression(ResolveVisitor.java:1047) at org.codehaus.groovy.control.ResolveVisitor.transform(ResolveVisitor.java:706) at org.codehaus.groovy.control.ResolveVisitor.transformDeclarationExpression(ResolveVisitor.java:1088) at org.codehaus.groovy.control.ResolveVisitor.transform(ResolveVisitor.java:698) at org.codehaus.groovy.ast.ClassCodeExpressionTransformer.visitExpressionStatement(ClassCodeExpressionTransformer.java:142) at org.codehaus.groovy.ast.stmt.ExpressionStatement.visit(ExpressionStatement.java:42) at org.codehaus.groovy.ast.CodeVisitorSupport.visitBlockStatement(CodeVisitorSupport.java:37) at org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitBlockStatement(ClassCodeVisitorSupport.java:166) at org.codehaus.groovy.control.ResolveVisitor.visitBlockStatement(ResolveVisitor.java:1318) at org.codehaus.groovy.ast.stmt.BlockStatement.visit(BlockStatement.java:71) at org.codehaus.groovy.control.ResolveVisitor.transformClosureExpression(ResolveVisitor.java:1040) at org.codehaus.groovy.control.ResolveVisitor.transform(ResolveVisitor.java:704) at org.codehaus.groovy.ast.expr.Expression.transformExpressions(Expression.java:51) at org.codehaus.groovy.ast.expr.ArgumentListExpression.transformExpression(ArgumentListExpression.java:69) at org.codehaus.groovy.control.ResolveVisitor.transform(ResolveVisitor.java:711) at org.codehaus.groovy.control.ResolveVisitor.transformMethodCallExpression(ResolveVisitor.java:1061) at org.codehaus.groovy.control.ResolveVisitor.transform(ResolveVisitor.java:702) at org.codehaus.groovy.ast.ClassCodeExpressionTransformer.visitExpressionStatement(ClassCodeExpressionTransformer.java:142) at org.codehaus.groovy.ast.stmt.ExpressionStatement.visit(ExpressionStatement.java:42) at org.codehaus.groovy.ast.CodeVisitorSupport.visitBlockStatement(CodeVisitorSupport.java:37) at org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitBlockStatement(ClassCodeVisitorSupport.java:166) at org.codehaus.groovy.control.ResolveVisitor.visitBlockStatement(ResolveVisitor.java:1318) at org.codehaus.groovy.ast.stmt.BlockStatement.visit(BlockStatement.java:71) at org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitClassCodeContainer(ClassCodeVisitorSupport.java:104) at org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitConstructorOrMethod(ClassCodeVisitorSupport.java:115) at org.codehaus.groovy.ast.ClassCodeExpressionTransformer.visitConstructorOrMethod(ClassCodeExpressionTransformer.java:53) at org.codehaus.groovy.control.ResolveVisitor.visitConstructorOrMethod(ResolveVisitor.java:201) at org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitMethod(ClassCodeVisitorSupport.java:126) at org.codehaus.groovy.ast.ClassNode.visitContents(ClassNode.java:1078) at org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitClass(ClassCodeVisitorSupport.java:53) at org.codehaus.groovy.control.ResolveVisitor.visitClass(ResolveVisitor.java:1261) at org.codehaus.groovy.control.ResolveVisitor.startResolving(ResolveVisitor.java:176) at org.codehaus.groovy.control.CompilationUnit$11.call(CompilationUnit.java:651) at org.codehaus.groovy.control.CompilationUnit.applyToSourceUnits(CompilationUnit.java:931) at org.codehaus.groovy.control.CompilationUnit.doPhaseOperation(CompilationUnit.java:593) at org.codehaus.groovy.control.CompilationUnit.compile(CompilationUnit.java:542) at groovy.lang.GroovyClassLoader.doParseClass(GroovyClassLoader.java:298) at groovy.lang.GroovyClassLoader.parseClass(GroovyClassLoader.java:268) at groovy.lang.GroovyShell.parseClass(GroovyShell.java:688) at groovy.lang.GroovyShell.parse(GroovyShell.java:700) at org.jenkinsci.plugins.workflow.cps.CpsGroovyShell.reparse(CpsGroovyShell.java:67) at org.jenkinsci.plugins.workflow.cps.CpsFlowExecution.parseScript(CpsFlowExecution.java:410) at org.jenkinsci.plugins.workflow.cps.CpsFlowExecution.start(CpsFlowExecution.java:373) at org.jenkinsci.plugins.workflow.job.WorkflowRun.run(WorkflowRun.java:213) at hudson.model.ResourceController.execute(ResourceController.java:98) at hudson.model.Executor.run(Executor.java:404) Caused by: java.lang.ClassNotFoundException: org.apache.ivy.Ivy at java.net.URLClassLoader.findClass(URLClassLoader.java:381) at java.lang.ClassLoader.loadClass(ClassLoader.java:424) at java.lang.ClassLoader.loadClass(ClassLoader.java:357) at org.eclipse.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:450) at org.eclipse.jetty.webapp.WebAppClassLoader.loadClass(WebAppClassLoader.java:403) ... 94 more Finished: FAILURE {code} ] |
Status | In Review [ 10005 ] | In Progress [ 3 ] |
Link | This issue depends on JENKINS-18349 [ JENKINS-18349 ] |
Status | In Progress [ 3 ] | Open [ 1 ] |
Status | Open [ 1 ] | In Progress [ 3 ] |
Status | In Progress [ 3 ] | In Review [ 10005 ] |
Remote Link | This issue links to "acceptance-test-harness PR 176 (Web Link)" [ 14745 ] |
Resolution | Fixed [ 1 ] | |
Status | In Review [ 10005 ] | Resolved [ 5 ] |
Component/s | pipeline-general [ 21692 ] |
Component/s | workflow-plugin [ 18820 ] |
Link | This issue is related to JENKINS-42307 [ JENKINS-42307 ] |
Component/s | workflow-cps-global-lib-plugin [ 21714 ] | |
Component/s | pipeline [ 21692 ] |
(I could have sworn this was already filed, but I cannot find it now. The idea was brought up during the Workflow Summit a couple months ago but perhaps I failed to record it.)
There are two major reasons why Grape support could be problematic here. First, binary dependencies (compiled to *.class) cannot participate in CPS transformation, and thus calls to libraries would be considered “native” methods which cannot survive a Jenkins restart. If the call does significant I/O, especially network I/O, this would make the flow less robust. (This consideration shows why this issue differs from JENKINS-18349; the plain Groovy plugin just makes a call to the standard embedded Groovy runtime, whereas Workflow uses its own CPS-transformed interpreter.)
Second, when running in Groovy sandbox mode, the normal case when running a secured Jenkins instance with a distinction between administrators and job maintainers, any native calls would have to whitelisted, which assumes they are unconditionally safe—which might not be true if, say, a URL handling library permits file-protocol URLs. This consideration is in common with other plugins allowing use of Groovy in Jenkins.
Both these considerations would also apply if the workflow definition were to support the optional binary classpath feature in the Script Security plugin (currently it does not).
While it is obviously not practical to do so for every useful Groovy library, in general it is best to create custom workflow steps for important operations. These can then be made to survive restarts (or slave disconnections) if necessary, and can perform any necessary input validation and/or access control checks. Where applicable the step can also interact with files in a remote (slave) workspace, which would be impossible if using a non-Jenkins-specific library directly.
If you need to perform some complex or expensive tasks with unrestricted Groovy physically running on a slave, it may be simplest and most effective to simply write that code in a *.groovy file in your workspace (for example, in an SCM checkout) and then use tool and sh/bat to run Groovy as an external process; or even put this stuff into a Gradle script, Groovy Maven plugin execution, etc. The workflow script itself should be limited to simple and extremely lightweight logical operations focused on orchestrating the overall flow of control and interacting with other Jenkins features—slave allocation, user input, and the like.