Uploaded image for project: 'Jenkins'
  1. Jenkins
  2. JENKINS-58407

Fail to call a Closure stored as a class attribute/field

    • workflow-cps 2.75

      simple groovy code, like this

      class SomeStruct {
          def aPointerToClosure
      }
      
      node {
          def st = new SomeStruct()
          st.aPointerToClosure = { println 'foobar' }
          st.aPointerToClosure()
      } 

      and even within groovy library, started yelling the following exception:

      java.lang.IllegalStateException: expected to call SomeStruct.aPointerToClosure but wound up catching org.jenkinsci.plugins.workflow.cps.CpsClosure2.call; see: https://jenkins.io/redirect/pipeline-cps-method-mismatches/ at org.jenkinsci.plugins.workflow.cps.CpsVmExecutorService.handleMismatch(CpsVmExecutorService.java:117) at 

      The issue's appears as of 2.71 (05 Jul 2019), with 2.70 works properly.

      [Changelog](https://plugins.jenkins.io/workflow-cps), among other things, states the following:

      Improvement: Print detailed warnings to the build log when CPS-transformed code is called in a non-CPS context where possible. The warnings link to https://jenkins.io/redirect/pipeline-cps-method-mismatches/ which gives additional context and some examples of how to fix common issues. (JENKINS-31314)

       

      Most likely, this is that "nice improvement"...

      Whole Stack Trace:

        11.906 [id=48] WARNING o.j.p.w.cps.CpsVmExecutorService#reportProblem: Unexpected exception in CPS VM thread: CpsFlowExecution[Owner[job/1:job #1]]  11.906 [id=48] WARNING o.j.p.w.cps.CpsVmExecutorService#reportProblem: Unexpected exception in CPS VM thread: CpsFlowExecution[Owner[job/1:job #1]]java.lang.IllegalStateException: expected to call SomeStruct.aPointerToClosure but wound up catching org.jenkinsci.plugins.workflow.cps.CpsClosure2.call; see: https://jenkins.io/redirect/pipeline-cps-method-mismatches/ at org.jenkinsci.plugins.workflow.cps.CpsVmExecutorService.handleMismatch(CpsVmExecutorService.java:117) at com.cloudbees.groovy.cps.impl.CpsCallableInvocation.checkMismatch(CpsCallableInvocation.java:63) at com.cloudbees.groovy.cps.impl.ContinuationGroup.methodCall(ContinuationGroup.java:94) at com.cloudbees.groovy.cps.impl.FunctionCallBlock$ContinuationImpl.dispatchOrArg(FunctionCallBlock.java:113) at com.cloudbees.groovy.cps.impl.FunctionCallBlock$ContinuationImpl.fixName(FunctionCallBlock.java:78) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at com.cloudbees.groovy.cps.impl.ContinuationPtr$ContinuationImpl.receive(ContinuationPtr.java:72) at com.cloudbees.groovy.cps.impl.ConstantBlock.eval(ConstantBlock.java:21) at com.cloudbees.groovy.cps.Next.step(Next.java:83) at com.cloudbees.groovy.cps.Continuable$1.call(Continuable.java:174) at com.cloudbees.groovy.cps.Continuable$1.call(Continuable.java:163) at org.codehaus.groovy.runtime.GroovyCategorySupport$ThreadCategoryInfo.use(GroovyCategorySupport.java:129) at org.codehaus.groovy.runtime.GroovyCategorySupport.use(GroovyCategorySupport.java:268) at com.cloudbees.groovy.cps.Continuable.run0(Continuable.java:163) at org.jenkinsci.plugins.workflow.cps.CpsThread.runNextChunk(CpsThread.java:186) at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.run(CpsThreadGroup.java:370) at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.access$200(CpsThreadGroup.java:93) at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:282) at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:270) at org.jenkinsci.plugins.workflow.cps.CpsVmExecutorService$2.call(CpsVmExecutorService.java:66) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at hudson.remoting.SingleLaneExecutorService$1.run(SingleLaneExecutorService.java:131) at jenkins.util.ContextResettingExecutorService$1.run(ContextResettingExecutorService.java:28) at jenkins.security.ImpersonatingExecutorService$1.run(ImpersonatingExecutorService.java:59) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748) 

          [JENKINS-58407] Fail to call a Closure stored as a class attribute/field

          Jesse Glick added a comment -

          the real value of pipelines for me is actual ability to program pipelines, put common part into share library etc.

          Other than for the sake of compatibility when migrating an existing corpus of Pipeline script from a Jenkins server, there is no real reason for a Jenkinsfile in JFR to be anything more than

          node {
            checkout scm
            sh 'bash run.sh'
          }
          

          with all the details being handled by some external programs. This is because the purpose of Pipeline script is to script Jenkins—allocate nodes, publish test or analysis results in visual form, trigger builds of other jobs, accept user input, model structure for Blue Ocean, etc.—none of which is possible inside JFR as currently conceived. (Well, if you had bundled a cloud plugin such as kubernetes, you may be able to script node allocation, in which case parallel + podTemplate + container + node would be an alternative idiom to a direct kubectl run.)

          not sure what are actual selling points for sandboxes

          The only reason I can think of to enable the sandbox in JFR is to help test behavior of scripts which you also plan to run in a Jenkins server. At any rate, JENKINS-58414 does not sound specific to the sandbox.

          Jesse Glick added a comment - the real value of pipelines for me is actual ability to program pipelines, put common part into share library etc. Other than for the sake of compatibility when migrating an existing corpus of Pipeline script from a Jenkins server, there is no real reason for a Jenkinsfile in JFR to be anything more than node { checkout scm sh 'bash run.sh' } with all the details being handled by some external programs. This is because the purpose of Pipeline script is to script Jenkins—allocate nodes, publish test or analysis results in visual form, trigger builds of other jobs, accept user input, model structure for Blue Ocean, etc.—none of which is possible inside JFR as currently conceived. (Well, if you had bundled a cloud plugin such as kubernetes , you may be able to script node allocation, in which case parallel + podTemplate + container + node would be an alternative idiom to a direct kubectl run .) not sure what are actual selling points for sandboxes The only reason I can think of to enable the sandbox in JFR is to help test behavior of scripts which you also plan to run in a Jenkins server. At any rate, JENKINS-58414 does not sound specific to the sandbox.

          Dicom J added a comment -

          jglick, I have never said that I have enabled sandbox anywhere. Actually I have it disabled, but still from time to time face security (sandbox) related exceptions and I suspect (sorry, I shouldn't do that, it's not my business) that the root cause of all these strange Groovy behaviors are due to the fact that at some point sandbox has been plugged in. maybe my suspicions are wrong, again it's not my business, but as I said I have to deal with it.

          Regarding JFR, I found it as very useful tool in development of pipelines and shared libraries as:
          1. Many people run it locally from docker against theirs local codebases of the same project/product. Everybody has it's own Jenkins running without interfering with others.

          2. I personally can run it from command line, actually from my vim's command line, it's how I've got used to do actual programming.
          3. I personally, don't like to deal with UIs.

          Also my/our Jenkinsfile comprises just 1 line of code to call the code from shared library, which loads source code base for target project from scm and then looks for *.groovy cicd related modules within that code base and dynamically loads them, looks for required interface inside, and plug them in, in which way actual pipeline is built dynamically (where closures are heavily used).

          So I really like that JFR exists, in many other products headless part goes first and UI is just an extension of UX. So many thanks to those who've come up with JFR...

          Dicom J added a comment - jglick , I have never said that I have enabled sandbox anywhere. Actually I have it disabled, but still from time to time face security (sandbox) related exceptions and I suspect (sorry, I shouldn't do that, it's not my business) that the root cause of all these strange Groovy behaviors are due to the fact that at some point sandbox has been plugged in. maybe my suspicions are wrong, again it's not my business, but as I said I have to deal with it. Regarding JFR, I found it as very useful tool in development of pipelines and shared libraries as: 1. Many people run it locally from docker against theirs local codebases of the same project/product. Everybody has it's own Jenkins running without interfering with others. 2. I personally can run it from command line, actually from my vim's command line, it's how I've got used to do actual programming. 3. I personally, don't like to deal with UIs. Also my/our Jenkinsfile comprises just 1 line of code to call the code from shared library, which loads source code base for target project from scm and then looks for *.groovy cicd related modules within that code base and dynamically loads them, looks for required interface inside, and plug them in, in which way actual pipeline is built dynamically (where closures are heavily used). So I really like that JFR exists, in many other products headless part goes first and UI is just an extension of UX. So many thanks to those who've come up with JFR...

          Jesse Glick added a comment -

          I have [the sandbox] disabled, but still from time to time face security (sandbox) related exceptions and I suspect […] that the root cause of all these strange Groovy behaviors are due to the fact that at some point sandbox has been plugged in

          No. Pipeline script is compiled with either one or two syntax transformers:

          • A CPS transformer, which is always enabled, though it skips methods marked @NonCPS. This permits a build to survive a Jenkins restart.
          • A sandbox transformer, if selected.

          (Actually it is even a bit more complicated than that: there is a generic sandbox transformer in the script-security plugin which can be applied to any Groovy scripting in Jenkins; and then the workflow-cps plugin includes a hybrid transformer which mixes the CPS transformer with the sandbox transformer.)

          tl;dr: if you run Pipeline script (including JFR) you are not running plain Groovy, and so there are corner cases where standard language features do not work as expected.

          Note that, like the sandbox, the CPS transform is pointless for JFR because there is no server to restart; if the JFR JVM dies, your build is dead and that is that. So it would be great to make JFR run your script as plain Groovy. It is not enough to just disable the CPS transformer, though, since the entire execution model of workflow-cps is built to assume this transform. We would need to develop a separate execution engine that just delegates to the default Groovy runtime while offering Pipeline steps and global variables in the binding. Would make JFR faster, smaller, and more usable. There is other stuff that does not add any value in JFR, like the durable-task plugin; it would be simpler and better for sh in JFR to just run the specified command and keep the stdout / stderr file descriptors open using plain old java.lang.Process (or hudson.Proc), like freestyle projects do in hudson.tasks.Shell.

          Jesse Glick added a comment - I have [the sandbox] disabled, but still from time to time face security (sandbox) related exceptions and I suspect […] that the root cause of all these strange Groovy behaviors are due to the fact that at some point sandbox has been plugged in No. Pipeline script is compiled with either one or two syntax transformers: A CPS transformer, which is always enabled, though it skips methods marked @NonCPS . This permits a build to survive a Jenkins restart. A sandbox transformer, if selected. (Actually it is even a bit more complicated than that: there is a generic sandbox transformer in the script-security plugin which can be applied to any Groovy scripting in Jenkins; and then the workflow-cps plugin includes a hybrid transformer which mixes the CPS transformer with the sandbox transformer.) tl;dr: if you run Pipeline script (including JFR) you are not running plain Groovy, and so there are corner cases where standard language features do not work as expected. Note that, like the sandbox, the CPS transform is pointless for JFR because there is no server to restart; if the JFR JVM dies, your build is dead and that is that. So it would be great to make JFR run your script as plain Groovy. It is not enough to just disable the CPS transformer, though, since the entire execution model of workflow-cps is built to assume this transform. We would need to develop a separate execution engine that just delegates to the default Groovy runtime while offering Pipeline steps and global variables in the binding. Would make JFR faster, smaller, and more usable. There is other stuff that does not add any value in JFR, like the durable-task plugin; it would be simpler and better for sh in JFR to just run the specified command and keep the stdout / stderr file descriptors open using plain old java.lang.Process (or hudson.Proc ), like freestyle projects do in hudson.tasks.Shell .

          Hi,

          is there any workaround to set isUnitTest to false in Jenkinsfile runner? We use it for running tests on travis which now all fail due to this situation :-/ Some sort of short term mitigation would be highly appreciated.

           

          Thanks,

          Florian

          Florian Wilhelm added a comment - Hi, is there any workaround to set isUnitTest to false in Jenkinsfile runner? We use it for running tests on travis which now all fail due to this situation :-/ Some sort of short term mitigation would be highly appreciated.   Thanks, Florian

          Jesse Glick added a comment -

          fwilhe Not as such, but you can almost certainly fix the actual issue (not just reduce it to a warning) by simply avoiding overly magical syntaxes in your Pipeline script to begin with. See discussion above.

          Jesse Glick added a comment - fwilhe Not as such, but you can almost certainly fix the actual issue (not just reduce it to a warning) by simply avoiding overly magical syntaxes in your Pipeline script to begin with. See discussion above.

          Andrew Bayer added a comment -

          PRs up.

          Andrew Bayer added a comment - PRs up.

          Andrew Bayer added a comment -

          groovy-cps merged, releasing.

          Andrew Bayer added a comment - groovy-cps merged, releasing.

          Dicom J added a comment -

          abayer,
          your fix https://github.com/cloudbees/groovy-cps/commit/93c916d482b63bf5ed46a84d56cb934401be2020#diff-1c76c1813ed2b2b2ac87244e44c14641
          is incorporated into groovy-cps-1.31, but the latest workflow-cps-2.74 still uses previous groovy-cps-1.30, https://github.com/jenkinsci/workflow-cps-plugin/blob/workflow-cps-2.74/pom.xml#L74 without the fix and so having that described here https://wiki.jenkins.io/display/JENKINS/Pipeline+CPS+method+mismatches#PipelineCPSmethodmismatches-Directinvocationofclosuresstoredinobjectfieldsormaps doesn't help much to solve the issue, as workaround (explicit call) is not in GA.

          So does anyone know when we may have the next cut of workflow-cps-2.75 with your fix? Thanks for any information.
           

          Dicom J added a comment - abayer , your fix  https://github.com/cloudbees/groovy-cps/commit/93c916d482b63bf5ed46a84d56cb934401be2020#diff-1c76c1813ed2b2b2ac87244e44c14641 is incorporated into groovy-cps-1.31, but the latest workflow-cps-2.74 still uses previous groovy-cps-1.30, https://github.com/jenkinsci/workflow-cps-plugin/blob/workflow-cps-2.74/pom.xml#L74  without the fix and so having that described here  https://wiki.jenkins.io/display/JENKINS/Pipeline+CPS+method+mismatches#PipelineCPSmethodmismatches-Directinvocationofclosuresstoredinobjectfieldsormaps  doesn't help much to solve the issue, as workaround (explicit call) is not in GA. So does anyone know when we may have the next cut of workflow-cps-2.75 with your fix? Thanks for any information.  

          Devin Nusbaum added a comment -

          A fix for this issue was just released in Pipeline: Groovy Plugin version 2.75.

          Devin Nusbaum added a comment - A fix for this issue was just released in Pipeline: Groovy Plugin version 2.75.

          Dicom J added a comment -

          Thanks, dnusbaum, for very good news, I've been waiting a while for this cut... Thanks a lot all of you, participated in getting it done!

          Dicom J added a comment - Thanks, dnusbaum , for very good news, I've been waiting a while for this cut... Thanks a lot all of you, participated in getting it done!

            abayer Andrew Bayer
            dicomj23 Dicom J
            Votes:
            3 Vote for this issue
            Watchers:
            11 Start watching this issue

              Created:
              Updated:
              Resolved: