Search code examples
groovyjenkins-pipelinejenkins-pluginsjenkins-job-dsljenkins-groovy

Is there any way to clean up a Jenkins Worflowjob workspace with a groovy script via Jenkins script console?


Why again this type of question?

This question seems to have been asked multiple times, but all the answers are irelevant for Jenkins Pipeline jobs (plugin: workflow-job).

Situation

I am migrating a bunch of old freestyle jobs from old Jenkins standalone server to a distributed Jenkins env and I've decided to convert them to Jenkins Pipeline jobs (can't use Blue ocean for it as the SCM is SVN.

Anyway, for some of the jobs is not desired to clean up their workspaces as they are sort of sanity/verification jobs and because the size of SVN checkout and built stuff is large (2GB in 20K files, just deleting it is so slow).

However I do occasionally (ad-hoc) need to delete a workspace of such jobs. And I don't want to do it by:

And I don't have r/w access to a FS on that slave node (which would be the easiest thing to do).

Googling

Quick search on the internet avalanched me with dozens of results [1,2, 3, 4, ...] how to cleanWS() from within a Groovy script ran from Jenkins script console.

Unfortunately, none of them tries to delete workspace of true org.jenkinsci.plugins.workflow.job.WorkflowJob item instance of a job.

My Groovy attempt to cleanWS

Based on the answers gathered from the internet I started my Groovy clean up script which can be executed from the Jenkins script console <Jenkins:port/script>

import hudson.model.*
import com.cloudbees.hudson.*
import com.cloudbees.hudson.plugins.*
import com.cloudbees.hudson.plugins.folder.*
import org.jenkinsci.plugins.workflow.job.*

//jobsToRetrieve = ["aFolder/aJobInFolder","topLevelJob"]
jobsToRetrieve = ["Sandbox/PipelineTests/SamplePipeline"]

enumerateItems(Hudson.instance.items)

def enumerateItems(items) {
  items.each { item ->
    println("===============::: GENERAL INFO::: =======================")
    println(" item: " + item)
    println(" item FN:  " + item.fullName)
    println(" item.getClass " + item.getClass())
    println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")

    if ( !(item instanceof Folder)) {
      jobName = item.getFullDisplayName()
      println(" :::jobname::: " + jobName)
      if (jobsToRetrieve.contains(item.getFullName())) {
        if (item instanceof WorkflowJob) {
          println("XXXXXXXXXXXXX--- THIS IS THE JOB --- XXXXXXXXXXXXXXXXXXXXX")
          println(" item.workspace: " + item.WORKSPACE)
          println("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
          println(" following methods ain't implemented for WorkflowJob type of Item\nand it will blow out.")
          //see https://javadoc.jenkins.io/hudson/model/FreeStyleProject.html
          println(" customWS: " + item.getCustomWorkspace())
          println(" WS:" + item.getWorkspace())
          item.doDoWipeOutWorkspace()
        }
      }
    } else {
        println(" :::foldername::: " + item.displayName)
        enumerateItems(((Folder) item).getItems())
    }
    println("==========================================================")
  }
}

Results (kinda expected, but disaponting)

as you can see, my script is going to explode on calls of:

item.getCustomWorkspace()
item.getWorkspace()
item.doDoWipeOutWorkspace()

with MissingMethodException

groovy.lang.MissingMethodException: No signature of method: org.jenkinsci.plugins.workflow.job.WorkflowJob.doDoWipeOutWorkspace() is applicable for argument types: () values: []
    at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:58)
    at org.codehaus.groovy.runtime.callsite.PojoMetaClassSite.call(PojoMetaClassSite.java:49)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:117)
    at Script1$_enumerateItems_closure1.doCall(Script1.groovy:33)

Simply because those methods ain't available for this type of item, but only for hudson.model.FreeStyleProject

Question: How then I can delete the Pipeline job's workspace?

There is another Jenkins plugin: Workspace Cleanup which is probably used within Jenkinsfile by calling cleanWs() inside a stage() {}, but I didn't figure out how to utilise it from the outside of Jenkinsfile (like from my groovy script ran Jenkins script console).

Is it a bug/request for enhancement of Jenkins Pipeline jobs plugin? Or is there any other way how to cast the item to something from where I would have access to a desired functionality?


Solution

  • Alright, investigating this more and googling even more and listening to your ideas (this one particularly inspired me by Daniel Spilker) I have achieved what I wanted, which is:

    Independently to CLEAN-UP Pipeline Job's WORKSPACE via Jenkins script console

    (only using Jenkins available means and no messing up with Job configuration, nor updating Jenkinsfile, nor replaying)

    The code is not surprisingly difficult and for manual demonstration it looks like this:

    Jenkins jenkins = Jenkins.instance
    Job item = jenkins.getItemByFullName('Sandbox/PipelineTests/SamplePipeline')
    println("RootDir: " + item.getRootDir())
    
    for (Node node in jenkins.nodes) {
      // Make sure slave is online
      if (!node.toComputer().online) {
        println "Node '$node.nodeName' is currently offline - skipping workspace cleanup"
        continue
      }
    
      println "Node '$node.nodeName' is online - performing cleanup:"
    
      // Do some cleanup
      FilePath wrksp = node.getWorkspaceFor(item)
      println("WRKSP "  + wrksp)
      println("ls " + wrksp.list())
      println("Free space " + wrksp.getFreeDiskSpace())
      println("===== PERFORMING CLEAN UP!!! =====")
      wrksp.deleteContents()
      println("ls now " + wrksp.list())
      println("Free space now " + wrksp.getFreeDiskSpace())
    }
    

    Its output, if your job is found, looks like:

    Result

    RootDir: /var/lib/jenkins/jobs/Sandbox/jobs/PipelineTests/jobs/SamplePipeline
    ....
    .... other node's output noise
    ....
    Node 'mcs-ubuntu-chch' is online - performing cleanup:
    WRKSP /var/lib/jenkins/workspace/Sandbox/PipelineTests/SamplePipeline
    ls [/var/lib/jenkins/workspace/Sandbox/PipelineTests/SamplePipeline/README.md, /var/lib/jenkins/workspace/Sandbox/PipelineTests/SamplePipeline/.git]
    Free space 3494574714880
    ===== PERFORMING CLEAN UP!!! =====
    ls now []
    Free space now 3494574919680
    

    Mission completed:)

    References

    Mainly Jenkins javadoc