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

expected to call CpsGroovyShell.evaluate but wound up catching <something>.run

    Details

    • Similar Issues:
    • Released As:
      workflow-cps 2.75

      Description

      We found a change that prints an annoying warning about the CPS mismatch during running the MPL module: https://github.com/griddynamics/mpl/issues/31

      Running on Jenkins in /var/jenkins_home/workspace/mpl-master
      [Pipeline] {
      [Pipeline] stage
      [Pipeline] { (Checkout)
      [Pipeline] fileExists
      expected to call org.jenkinsci.plugins.workflow.cps.CpsGroovyShell.evaluate but wound up catching Checkout.run; see: https://jenkins.io/redirect/pipeline-cps-method-mismatches/

      We're not quite sure how to fix that in the library, but realized that the issue is related to the change JENKINS-31314 introduced in workflow-cps-2.71.

      Reproduce is quite simple - just need to install the minimal latest jenkins, add required git & shared lib plugins, attach mpl library from github and create a simple jenkins job to build the mpl. It will fail (no Maven 3 tool) - but will show the issue during each module start.

      Who could help with determining the actual cause and how to fix that?

        Attachments

          Issue Links

            Activity

            sparshev Sergei Parshev created issue -
            sparshev Sergei Parshev made changes -
            Field Original Value New Value
            Link This issue is caused by JENKINS-31314 [ JENKINS-31314 ]
            Hide
            sparshev Sergei Parshev added a comment -

            Jesse Glick, Devin Nusbaum - could you please check? Probably jenkins shouldn't show such messages in the job log?

            Show
            sparshev Sergei Parshev added a comment - Jesse Glick , Devin Nusbaum - could you please check? Probably jenkins shouldn't show such messages in the job log?
            sparshev Sergei Parshev made changes -
            Priority Minor [ 4 ] Major [ 3 ]
            Hide
            jglick Jesse Glick added a comment -

            Is there a self-contained minimal test case to reproduce the issue? Preferably just a single Jenkinsfile with all inessential lines removed.

            Show
            jglick Jesse Glick added a comment - Is there a self-contained minimal test case to reproduce the issue? Preferably just a single Jenkinsfile with all inessential lines removed.
            sparshev Sergei Parshev made changes -
            Assignee Sergei Parshev [ sparshev ]
            Hide
            sparshev Sergei Parshev added a comment -

            Hi Jesse Glick,

            Unfortunately it's impossible to prepare just a Jenkinsfile - MPL is a shared library. We already tracked down the issue - and found, that the message are produced during the module run in Helper.groovy:

              static void runModule(String src, String path, Map vars = [:]) {
                getShell(vars).evaluate(src, path)
              }
            

            If we using the minimal Jeninsfile from the MPL repo, the call tracepath to the first `Checkout` module "expected to call" message looks like this:

            This issue is not critical, but prints the verbose information that looks weird and not helpful for the end users...

            Show
            sparshev Sergei Parshev added a comment - Hi Jesse Glick , Unfortunately it's impossible to prepare just a Jenkinsfile - MPL is a shared library. We already tracked down the issue - and found, that the message are produced during the module run in Helper.groovy: static void runModule(String src, String path, Map vars = [:]) { getShell(vars).evaluate(src, path) } If we using the minimal Jeninsfile from the MPL repo , the call tracepath to the first `Checkout` module "expected to call" message looks like this: MPLPipeline() MPLModule() Helper.runModule() CPSGroovyShell.evaluate() Message: `expected to call org.jenkinsci.plugins.workflow.cps.CpsGroovyShell.evaluate but wound up catching Checkout.run; see: https://jenkins.io/redirect/pipeline-cps-method-mismatches/ ` This issue is not critical, but prints the verbose information that looks weird and not helpful for the end users...
            Hide
            jglick Jesse Glick added a comment -

            MPL is a shared library

            I understand that, but I suspect that the trigger condition for the bug could be narrowed down to something which could be written in a single short script, perhaps using some local function definitions or whatever. Even if it is actually impossible to reproduce without a library, then the minimal self-contained test case would be a minimal library (probably one source file with a few lines) and an accompanying Jenkinsfile.

            Show
            jglick Jesse Glick added a comment - MPL is a shared library I understand that, but I suspect that the trigger condition for the bug could be narrowed down to something which could be written in a single short script, perhaps using some local function definitions or whatever. Even if it is actually impossible to reproduce without a library, then the minimal self-contained test case would be a minimal library (probably one source file with a few lines) and an accompanying Jenkinsfile .
            Hide
            sparshev Sergei Parshev added a comment -

            Ok, I think I can prepare a simple vars-only shared lib with such call.

            Show
            sparshev Sergei Parshev added a comment - Ok, I think I can prepare a simple vars-only shared lib with such call.
            Hide
            sparshev Sergei Parshev added a comment -

            What I've done:

            1. Started 2.176.2 jenkins with the next plugins.txt:
              • git
              • workflow-aggregator
            2. Added shared library "test" with the local repo in /var/jenkins_home/test_shared_lib and "master" version by default
            3. Init git repo /var/jenkins_home/test_shared_lib and created commit with the next content:
              • vars/executeGroovyScript.groovy
                import org.jenkinsci.plugins.workflow.cps.CpsGroovyShellFactory
                import org.jenkinsci.plugins.workflow.cps.CpsThread
                
                def call(String src, String path, Map vars = [:]) {
                  getShell(vars).evaluate(src, path)
                }
                
                def getShell(Map vars = [:]) {
                  def ex = CpsThread.current().getExecution()
                  def shell = new CpsGroovyShellFactory(ex).withParent(ex.getShell()).build()
                  vars.each { key, val -> shell.setVariable(key, val) }
                  shell
                }
                
            4. Created test job with pipeline script:
              @Library('test') _
              
              executeGroovyScript('echo "hello world"', 'Module.groovy')
              

            And the job execution result is:

            Started by user unknown or anonymous
            Running in Durability level: MAX_SURVIVABILITY
            Loading library test@master
            Attempting to resolve master from remote references...
             > git --version # timeout=10
             > git ls-remote -h /var/jenkins_home/test_shared_lib # timeout=10
            Found match: refs/heads/master revision a8aa6eeacb2a84f533d33ca4bd6cb4851aa95dd5
            No credentials specified
             > git rev-parse --is-inside-work-tree # timeout=10
            Fetching changes from the remote Git repository
             > git config remote.origin.url /var/jenkins_home/test_shared_lib # timeout=10
            Fetching without tags
            Fetching upstream changes from /var/jenkins_home/test_shared_lib
             > git --version # timeout=10
             > git fetch --no-tags --force --progress /var/jenkins_home/test_shared_lib +refs/heads/*:refs/remotes/origin/*
            Checking out Revision a8aa6eeacb2a84f533d33ca4bd6cb4851aa95dd5 (master)
             > git config core.sparsecheckout # timeout=10
             > git checkout -f a8aa6eeacb2a84f533d33ca4bd6cb4851aa95dd5
            Commit message: "Init"
             > git rev-list --no-walk b3d7243e87528f2a8971101d2b93c8eeba904466 # timeout=10
            [Pipeline] Start of Pipeline
            expected to call org.jenkinsci.plugins.workflow.cps.CpsGroovyShell.evaluate but wound up catching Module.run; see: https://jenkins.io/redirect/pipeline-cps-method-mismatches/
            [Pipeline] echo
            hello world
            [Pipeline] End of Pipeline
            Finished: SUCCESS
            
            Show
            sparshev Sergei Parshev added a comment - What I've done: Started 2.176.2 jenkins with the next plugins.txt: git workflow-aggregator Added shared library "test" with the local repo in /var/jenkins_home/test_shared_lib and "master" version by default Init git repo /var/jenkins_home/test_shared_lib and created commit with the next content: vars/executeGroovyScript.groovy import org.jenkinsci.plugins.workflow.cps.CpsGroovyShellFactory import org.jenkinsci.plugins.workflow.cps.CpsThread def call(String src, String path, Map vars = [:]) { getShell(vars).evaluate(src, path) } def getShell(Map vars = [:]) { def ex = CpsThread.current().getExecution() def shell = new CpsGroovyShellFactory(ex).withParent(ex.getShell()).build() vars.each { key, val -> shell.setVariable(key, val) } shell } Created test job with pipeline script: @Library('test') _ executeGroovyScript('echo "hello world"', 'Module.groovy') And the job execution result is: Started by user unknown or anonymous Running in Durability level: MAX_SURVIVABILITY Loading library test@master Attempting to resolve master from remote references... > git --version # timeout=10 > git ls-remote -h /var/jenkins_home/test_shared_lib # timeout=10 Found match: refs/heads/master revision a8aa6eeacb2a84f533d33ca4bd6cb4851aa95dd5 No credentials specified > git rev-parse --is-inside-work-tree # timeout=10 Fetching changes from the remote Git repository > git config remote.origin.url /var/jenkins_home/test_shared_lib # timeout=10 Fetching without tags Fetching upstream changes from /var/jenkins_home/test_shared_lib > git --version # timeout=10 > git fetch --no-tags --force --progress /var/jenkins_home/test_shared_lib +refs/heads/*:refs/remotes/origin/* Checking out Revision a8aa6eeacb2a84f533d33ca4bd6cb4851aa95dd5 (master) > git config core.sparsecheckout # timeout=10 > git checkout -f a8aa6eeacb2a84f533d33ca4bd6cb4851aa95dd5 Commit message: "Init" > git rev-list --no-walk b3d7243e87528f2a8971101d2b93c8eeba904466 # timeout=10 [Pipeline] Start of Pipeline expected to call org.jenkinsci.plugins.workflow.cps.CpsGroovyShell.evaluate but wound up catching Module.run; see: https://jenkins.io/redirect/pipeline-cps-method-mismatches/ [Pipeline] echo hello world [Pipeline] End of Pipeline Finished: SUCCESS
            Hide
            jglick Jesse Glick added a comment -

            Explicit use of org.jenkinsci.plugins.workflow.cps.* implementation classes cannot be considered supported. What exactly is this code attempting to accomplish?

            Show
            jglick Jesse Glick added a comment - Explicit use of org.jenkinsci.plugins.workflow.cps.* implementation classes cannot be considered supported. What exactly is this code attempting to accomplish?
            Hide
            sparshev Sergei Parshev added a comment -

            This logic is executing content `src` in sandbox as the original pipeline - MPL purpose is to separate the pipeline logic into modules. So this function is basic for the library - it creates another CPS shell with only variables provided into the script.

            Show
            sparshev Sergei Parshev added a comment - This logic is executing content `src` in sandbox as the original pipeline - MPL purpose is to separate the pipeline logic into modules. So this function is basic for the library - it creates another CPS shell with only variables provided into the script.
            Hide
            jglick Jesse Glick added a comment -

            Normally this sort of thing would be handled with simple closures etc., not evaluate. Since this is a nonstandard usage, I would consider the priority low.

            There was an effort (since backed out) to offer an SPI by which plugins with exotic workflow-cps usages could suppress the warnings for their special call patterns, but that would be of no use to you anyway.

            Show
            jglick Jesse Glick added a comment - Normally this sort of thing would be handled with simple closures etc., not evaluate . Since this is a nonstandard usage, I would consider the priority low. There was an effort (since backed out) to offer an SPI by which plugins with exotic workflow-cps usages could suppress the warnings for their special call patterns, but that would be of no use to you anyway.
            Hide
            jglick Jesse Glick added a comment -

            I suspect this issue has nothing to do with libraries per se and could be reproduced in a self-contained Jenkinsfile. Maybe

            def ex = CpsThread.current().execution
            new CpsGroovyShellFactory(ex).withParent(ex.shell).build().evaluate('echo "OK"', 'X.groovy')
            

            or maybe even just

            evaluate('echo "OK"', 'X.groovy')
            

            since I think existing tests only cover the overload taking only a single String parameter.

            If so, it is a bug somewhere in the way evaluate is being handled, and is probably very easy to fix in groovy-cps.

            Show
            jglick Jesse Glick added a comment - I suspect this issue has nothing to do with libraries per se and could be reproduced in a self-contained Jenkinsfile . Maybe def ex = CpsThread.current().execution new CpsGroovyShellFactory(ex).withParent(ex.shell).build().evaluate( 'echo "OK" ' , 'X.groovy' ) or maybe even just evaluate( 'echo "OK" ' , 'X.groovy' ) since I think existing tests only cover the overload taking only a single String parameter. If so, it is a bug somewhere in the way evaluate is being handled, and is probably very easy to fix in groovy-cps .
            Hide
            sparshev Sergei Parshev added a comment - - edited

            Probably you can use CpsThread or CpsGroovyShellFactory without sandbox flag - but we're worrying about the security - and don't allow modules/scripts to be used with the shared library permissions. We preparing pipelines in the shared library (because pipelines are common) and executing their logic (stored in modules) again in the sandbox with help of the CpsGroovyShell.

            Just `evaluate()` is almost the same - but the reason to use a separated CpsGroovyShell - is to enclave the script and to bind a special variables (`CFG` from the MPLModule.groovy).

            Yeah, it's low priority, but there is a way to move such messages into the jenkins master log for example? I think it's not a useful message for the ones, who actually want to see the build log...

            What do you think about the solutions? Maybe I can help with the implementation?

            Show
            sparshev Sergei Parshev added a comment - - edited Probably you can use CpsThread or CpsGroovyShellFactory without sandbox flag - but we're worrying about the security - and don't allow modules/scripts to be used with the shared library permissions. We preparing pipelines in the shared library (because pipelines are common) and executing their logic (stored in modules) again in the sandbox with help of the CpsGroovyShell. Just `evaluate()` is almost the same - but the reason to use a separated CpsGroovyShell - is to enclave the script and to bind a special variables (`CFG` from the MPLModule.groovy). Yeah, it's low priority, but there is a way to move such messages into the jenkins master log for example? I think it's not a useful message for the ones, who actually want to see the build log... What do you think about the solutions? Maybe I can help with the implementation?
            Hide
            jglick Jesse Glick added a comment -

            there is a way to move such messages into the jenkins master log

            No, this would hide the critical diagnostic information from the people writing Pipelines who are normally responsible for making mistakes here.

            The first step is to have a PR up with an addition to the existing @Ignore’d test case demonstrating the problem using the shortest possible script, possibly something like one of the above examples. In that case, a fix in groovy-cps is likely possible.

            Show
            jglick Jesse Glick added a comment - there is a way to move such messages into the jenkins master log No, this would hide the critical diagnostic information from the people writing Pipelines who are normally responsible for making mistakes here. The first step is to have a PR up with an addition to the existing @Ignore ’d test case demonstrating the problem using the shortest possible script, possibly something like one of the above examples. In that case, a fix in groovy-cps is likely possible.
            Hide
            sparshev Sergei Parshev added a comment -

            Hi Jesse Glick, ok I got it - if it's not about security, but about a simple example to show that we need an exception in the warning logic: I tested with turned off sandbox - found a minimal implementation to show the issue:

            • Jenkinsfile:
              org.jenkinsci.plugins.workflow.cps.CpsThread.current().getExecution().getShell().evaluate('echo "OK"', 'X.groovy')
              
            • Output:
              Started by user unknown or anonymous
              Running in Durability level: MAX_SURVIVABILITY
              [Pipeline] Start of Pipeline
              expected to call org.jenkinsci.plugins.workflow.cps.CpsGroovyShell.evaluate but wound up catching X.run; see: https://jenkins.io/redirect/pipeline-cps-method-mismatches/
              [Pipeline] echo
              OK
              [Pipeline] End of Pipeline
              Finished: SUCCESS
              
            Show
            sparshev Sergei Parshev added a comment - Hi Jesse Glick , ok I got it - if it's not about security, but about a simple example to show that we need an exception in the warning logic: I tested with turned off sandbox - found a minimal implementation to show the issue: Jenkinsfile: org.jenkinsci.plugins.workflow.cps.CpsThread.current().getExecution().getShell().evaluate('echo "OK"', 'X.groovy') Output: Started by user unknown or anonymous Running in Durability level: MAX_SURVIVABILITY [Pipeline] Start of Pipeline expected to call org.jenkinsci.plugins.workflow.cps.CpsGroovyShell.evaluate but wound up catching X.run; see: https://jenkins.io/redirect/pipeline-cps-method-mismatches/ [Pipeline] echo OK [Pipeline] End of Pipeline Finished: SUCCESS
            Hide
            sparshev Sergei Parshev added a comment - - edited

            I think there is two ways to fix the issue:

            1. Prepare overload for evaluate function to be able to execute groovy logic with providing the src path and bindings
            2. Prepare an exception for executing CpsGroovyShell.evaluate https://github.com/cloudbees/groovy-cps/pull/99

            Jesse Glick what do you think will be better? Easier for sure prepare an exception hack, but probably that will be appropriate to modify the evaluate step?

            Or maybe even prepare `module` step and put such MPL functionality into the Jenkins itself? I'm just not sure that it's a good idea because probably I will need to prepare an additional plugin and I would avoid that and keep minimal requirements for the MPL library.

            Show
            sparshev Sergei Parshev added a comment - - edited I think there is two ways to fix the issue: Prepare overload for evaluate function to be able to execute groovy logic with providing the src path and bindings Prepare an exception for executing CpsGroovyShell.evaluate https://github.com/cloudbees/groovy-cps/pull/99 Jesse Glick what do you think will be better? Easier for sure prepare an exception hack, but probably that will be appropriate to modify the evaluate step? Or maybe even prepare `module` step and put such MPL functionality into the Jenkins itself? I'm just not sure that it's a good idea because probably I will need to prepare an additional plugin and I would avoid that and keep minimal requirements for the MPL library.
            jglick Jesse Glick made changes -
            Summary MPL shared library logic execution caused CPS mismatch warning expected to call CpsGroovyShell.evaluate but wound up catching <something>.run
            Hide
            jglick Jesse Glick added a comment -

            A patch to groovy-cps as in #2 would be the appropriate fix, I think. If we are entering certain overloads of GroovyShell.evaluate and we get a continuation from some Script.run implementation, then all is well and there should be no warning.

            Show
            jglick Jesse Glick added a comment - A patch to groovy-cps as in #2 would be the appropriate fix, I think. If we are entering certain overloads of GroovyShell.evaluate and we get a continuation from some Script.run implementation, then all is well and there should be no warning.
            Hide
            sparshev Sergei Parshev added a comment -

            Thank you, I will prepare an implementation with tests for this case.

            Show
            sparshev Sergei Parshev added a comment - Thank you, I will prepare an implementation with tests for this case.
            Hide
            sparshev Sergei Parshev added a comment -

            Ok, just prepared a couple of PR's:

            Jesse Glick could you please check them?

            Show
            sparshev Sergei Parshev added a comment - Ok, just prepared a couple of PR's: https://github.com/cloudbees/groovy-cps/pull/101 - with the exception implementation https://github.com/jenkinsci/workflow-cps-plugin/pull/315 - with the test of the minimal Jenkinsfile Jesse Glick could you please check them?
            Hide
            abayer Andrew Bayer added a comment -

            I've merged the groovy-cps PR and will be cutting a release today.

            Show
            abayer Andrew Bayer added a comment - I've merged the groovy-cps PR and will be cutting a release today.
            Hide
            sparshev Sergei Parshev added a comment -

            The changes of PR#315 was merged to the master of workflow-cps-plugin - so hopefully will be available in the next release 2.75

            Show
            sparshev Sergei Parshev added a comment - The changes of PR#315 was merged to the master of workflow-cps-plugin - so hopefully will be available in the next release 2.75
            dnusbaum Devin Nusbaum made changes -
            Remote Link This issue links to "cloudbees/groovy-cps#101 (Web Link)" [ 23911 ]
            dnusbaum Devin Nusbaum made changes -
            Remote Link This issue links to "jenkinsci/workflow-cps-plugin#315 (Web Link)" [ 23912 ]
            Hide
            dnusbaum Devin Nusbaum added a comment -

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

            Show
            dnusbaum Devin Nusbaum added a comment - A fix for this issue was just released in Pipeline: Groovy Plugin version 2.75.
            dnusbaum Devin Nusbaum made changes -
            Status Open [ 1 ] Resolved [ 5 ]
            Resolution Fixed [ 1 ]
            Released As workflow-cps 2.75
            Show
            sparshev Sergei Parshev added a comment - Yep, confirmed here: https://github.com/griddynamics/mpl/issues/31#issuecomment-548919000
            sparshev Sergei Parshev made changes -
            Status Resolved [ 5 ] Closed [ 6 ]

              People

              • Assignee:
                sparshev Sergei Parshev
                Reporter:
                sparshev Sergei Parshev
              • Votes:
                0 Vote for this issue
                Watchers:
                5 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved: