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

LinkageError loader attempted duplicate class definition for name causes Jenkins to doesn't start

    XMLWordPrintable

    Details

    • Similar Issues:

      Description

      Using load step to load two different groovy files without an explicit class but the same package declaration, causes Jenkins to fail during startup process if the build should be resumed.

      For example, create a dummy pipeline like

      def util
      def config
      def util2
      
      node('master') {
          sh 'cp -r /tmp/test/src .'
      
          config = load 'src/org/foo/devops/JenkinsEnvironment.groovy'
          util = load 'src/org/foo/devops/Utility.groovy'
      
          config.loadProdConfiguration()    
      }
      util.isValueExist("")
      
      echo "kill me while I'm sleeping"
      sleep 20
      
      node('master') {
          util2 = load 'src/org/foo/devops/Utility.groovy'
          util = load 'src/org/foo/devops/Utility.groovy'
      }
      

      And copy the two attached files at /tmp/test/src/org/foo/devops/
      (Files can be retrieved as you prefer)

      Build the job and restart jenkins while is building.

      Then you won't be able to access Jenkins.

        Attachments

        1. JenkinsEnvironment.groovy
          0.1 kB
        2. startup-error.log
          8 kB
        3. startup-page.log
          3 kB
        4. Utility.groovy
          0.2 kB

          Issue Links

            Activity

            Hide
            svanoort Sam Van Oort added a comment -

            Downgrading the priority because this requires badly malformed code to cause issues and seems rather niche and easily fixed user-side ("do not do that").

            Show
            svanoort Sam Van Oort added a comment - Downgrading the priority because this requires badly malformed code to cause issues and seems rather niche and easily fixed user-side ("do not do that").
            Hide
            abayer Andrew Bayer added a comment -

            I'd say this is just a symptom of JENKINS-50172.

            Show
            abayer Andrew Bayer added a comment - I'd say this is just a symptom of JENKINS-50172 .
            Hide
            abayer Andrew Bayer added a comment -

            Comment copied over from JENKINS-50172:

            The problem appears to stem from the fact that load will actually give everything an autogenerated class name (i.e., Script1, Script2, etc). This is because load doesn't actually parse/compile the file passed to it directly - it reads that file (so, in this case, src/org/foo/devops/Utility.groovy), and parses it directly, autogenerating the class name. But when there's a package, things get...confused. The resulting loadedScripts key in CpsFlowExecution ends up as org.foo.devops.Script1, rather than Script1. Which is fine? I guess? Well, until we try to resume. Then, when we get to CpsFlowExecution#parseScript(), we end up trying to CpsGroovyShell#parse(new GroovyCodeSource("code from Utility.groovy", "org.foo.devops.Script1", DEFAULT_CODE_BASE)), and that confuses Groovy's parsing logic: if you tell it "here's a class name including package to parse, and here's the text to parse", it's going to get very confused when there's no class Script1 inside that text. So it ends up deciding the fully qualified class name is "(package).(package but with periods replaced by underscores)" for...reasons? And that results in duplicate class names and everything blows up.

            So for the moment? Don't put package ... in Groovy files you're going to load. It will break things. Obviously. I think the fix for this is to just put getClass().getSimpleName() in as the key in CpsFlowExecution#loadedScripts rather than the current getClass().getName() - this definitely fixes this problem but I'm a bit wary as to whether there could be side effects. And regardless of that fix, I would not be at all surprised if there were other weird edge cases around load and packages, so...just don't do that.

            Show
            abayer Andrew Bayer added a comment - Comment copied over from JENKINS-50172 : The problem appears to stem from the fact that load will actually give everything an autogenerated class name (i.e., Script1 , Script2 , etc). This is because load doesn't actually parse/compile the file passed to it directly - it reads that file (so, in this case, src/org/foo/devops/Utility.groovy ), and parses it directly, autogenerating the class name. But when there's a package, things get...confused. The resulting loadedScripts key in CpsFlowExecution ends up as org.foo.devops.Script1 , rather than Script1 . Which is fine? I guess? Well, until we try to resume. Then, when we get to CpsFlowExecution#parseScript() , we end up trying to CpsGroovyShell#parse(new GroovyCodeSource("code from Utility.groovy", "org.foo.devops.Script1", DEFAULT_CODE_BASE)) , and that confuses Groovy's parsing logic: if you tell it "here's a class name including package to parse, and here's the text to parse", it's going to get very confused when there's no class Script1 inside that text. So it ends up deciding the fully qualified class name is "(package).(package but with periods replaced by underscores)" for...reasons? And that results in duplicate class names and everything blows up. So for the moment? Don't put package ... in Groovy files you're going to load . It will break things. Obviously. I think the fix for this is to just put getClass().getSimpleName() in as the key in CpsFlowExecution#loadedScripts rather than the current getClass().getName() - this definitely fixes this problem but I'm a bit wary as to whether there could be side effects. And regardless of that fix, I would not be at all surprised if there were other weird edge cases around load and packages, so...just don't do that.
            Hide
            abayer Andrew Bayer added a comment -

            Yeah, switching to getSimpleName() seems to be the right answer, so PR up at https://github.com/jenkinsci/workflow-cps-plugin/pull/214

            Show
            abayer Andrew Bayer added a comment - Yeah, switching to getSimpleName() seems to be the right answer, so PR up at https://github.com/jenkinsci/workflow-cps-plugin/pull/214
            Hide
            scm_issue_link SCM/JIRA link daemon added a comment -

            Code changed in jenkins
            User: Andrew Bayer
            Path:
            src/main/java/org/jenkinsci/plugins/workflow/cps/CpsGroovyShell.java
            src/test/java/org/jenkinsci/plugins/workflow/cps/steps/RestartingLoadStepTest.java
            http://jenkins-ci.org/commit/workflow-cps-plugin/73d11f26e2bc2f56fb1cf42ab53ec326d2d9ad25
            Log:
            [FIXED JENKINS-50171] Don't use package names in loadedScripts keys.

            It just makes things go badly.

            Show
            scm_issue_link SCM/JIRA link daemon added a comment - Code changed in jenkins User: Andrew Bayer Path: src/main/java/org/jenkinsci/plugins/workflow/cps/CpsGroovyShell.java src/test/java/org/jenkinsci/plugins/workflow/cps/steps/RestartingLoadStepTest.java http://jenkins-ci.org/commit/workflow-cps-plugin/73d11f26e2bc2f56fb1cf42ab53ec326d2d9ad25 Log: [FIXED JENKINS-50171] Don't use package names in loadedScripts keys. It just makes things go badly.
            Hide
            abayer Andrew Bayer added a comment -

            Fixed in the upcoming workflow-cps 2.46 release.

            Show
            abayer Andrew Bayer added a comment - Fixed in the upcoming workflow-cps 2.46 release.

              People

              • Assignee:
                abayer Andrew Bayer
                Reporter:
                escoem Emilio Escobar
              • Votes:
                0 Vote for this issue
                Watchers:
                4 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved: