Skip to content

Instantly share code, notes, and snippets.

@EvilBeaver
Forked from rb2k/gist:8372402
Last active October 18, 2023 10:15
Show Gist options
  • Star 47 You must be signed in to star a gist
  • Fork 31 You must be signed in to fork a gist
  • Save EvilBeaver/35ebded526fb53ecb9716889c1de11df to your computer and use it in GitHub Desktop.
Save EvilBeaver/35ebded526fb53ecb9716889c1de11df to your computer and use it in GitHub Desktop.
A jenkins script to clean up workspaces on slaves
// Check if a slave has < 10 GB of free space, wipe out workspaces if it does
import hudson.model.*;
import hudson.util.*;
import jenkins.model.*;
import hudson.FilePath.FileCallable;
import hudson.slaves.OfflineCause;
import hudson.node_monitors.*;
def performCleanup(def node, def items) {
for (item in items) {
jobName = item.getFullDisplayName()
println("Cleaning " + jobName)
if(item instanceof com.cloudbees.hudson.plugins.folder.AbstractFolder) {
performCleanup(node, item.items)
continue
}
if (item.isBuilding()) {
println(".. job " + jobName + " is currently running, skipped")
continue
}
println(".. wiping out workspaces of job " + jobName)
workspacePath = node.getWorkspaceFor(item)
if (workspacePath == null) {
println(".... could not get workspace path")
continue
}
println(".... workspace = " + workspacePath)
pathAsString = workspacePath.getRemote()
if (workspacePath.exists()) {
workspacePath.deleteRecursive()
println(".... deleted from location " + pathAsString)
} else {
println(".... nothing to delete at " + pathAsString)
}
}
}
for (node in Jenkins.instance.nodes) {
computer = node.toComputer()
if (computer.getChannel() == null) continue
rootPath = node.getRootPath()
size = DiskSpaceMonitor.DESCRIPTOR.get(computer).size
roundedSize = size / (1024 * 1024 * 1024) as int
println("node: " + node.getDisplayName() + ", free space: " + roundedSize + "GB")
computer.setTemporarilyOffline(true, new hudson.slaves.OfflineCause.ByCLI("disk cleanup"))
performCleanup(node, Jenkins.instance.items)
computer.setTemporarilyOffline(false, null)
}
@TheNitek
Copy link

TheNitek commented Mar 5, 2018

Nice, works perfectly for me!

@jogamol
Copy link

jogamol commented Jun 21, 2018

works great. Thanks

@vimalkrishna
Copy link

This saved my lots of time writing on my own and Script works on script console of Jenkins (Master)!!
But as a system groovy script through a jenkins job, the latest groovy plugin (v2)doesn't work. We need to downgrade groovy plugin to 1.5 version and have minimum v 1.25 as script security plugin on Ubuntu 16. Also need to enable In-process Script Approval from Jenkins --> Manage Jenkins. Simple hint: Both master /slave machine must have groovy runtime installed with GROOVY_HOME set.

@kusumat
Copy link

kusumat commented May 16, 2019

Hi,
Why we are checking for instanceof com.cloudbees.hudson.plugins.folder.AbstractFolder
Why dont we simply delete the workspace?

Thanks

@Dretch
Copy link

Dretch commented Jun 20, 2019

Be aware that this script will skip jobs that are running, even if those jobs are not actually using any workspaces.

If you have pipeline jobs that are waiting for input, for example, then their workspaces will not be cleaned up by this script.

@EvilBeaver
Copy link
Author

If you have pipeline jobs that are waiting for input, for example, then their workspaces will not be cleaned up by this script.

I think this is a good behavior. It's not very polite to spoil life of running job, isn't it?

@tullurimanasa
Copy link

Hi, Thank you for sharing the snippet.I am testing this on my jenkins and it fails with below error. How do we skip FolderTemplate as isBuilding is not applicable for folder templates. Please advise.
hudson.remoting.ProxyException: groovy.lang.MissingMethodException: No signature of method: com.cloudbees.hudson.plugins.modeling.impl.folder.FolderTemplate.isBuilding() is applicable for argument types: () values: []

@MichaelKorn
Copy link

@EvilBeaver THX for sharing
Maybe someone is interested, I added a function to skip younger build:

    buildAgeDays = (System.currentTimeMillis() - item.getLastBuild().getTimeInMillis()) / (1000*60*60*24)
    if(buildAgeDays < 5 ){
      println(".. job " + jobName + " was recently running, last build: " + item.getLastBuild().getTimestampString())
      continue
    }

@fabjsousa
Copy link

Hello,

It's possible to run this script remotely?

I have zabbix monitoring my jenkins slaves for space usage. Now I'm trying to setup the groovy script to run when the workspace > 90%. So I have to run the command remotely from my zabbix server....

@EvilBeaver
Copy link
Author

@winnertako, have no idea. Try to google remote jenkins script execution

@menvol3
Copy link

menvol3 commented Mar 10, 2020

Hello,
i'm new with jenkins
Could you please tell where i can change the size from 10 gb, for example to 50 gb to delete files
And also is there any option to run this script only for custom nodes, not on all existing in jenkins ?
Thank You

@EvilBeaver
Copy link
Author

@menvol3 as long as I can see, current version wipes everything, regardless of free space. It seems comment in the first line is lying.

@paladin-dranser
Copy link

@menvol3

Hello,
i'm new with jenkins
Could you please tell where i can change the size from 10 gb, for example to 50 gb to delete files
And also is there any option to run this script only for custom nodes, not on all existing in jenkins ?
Thank You

As I understand, the first line (comment) is left from original script (see Forked from rb2k/gist:8372402 on the top page). The original script has if statement to check if free space is less than 10 GB: https://gist.github.com/rb2k/8372402#file-gistfile1-groovy-L19

@dracorp
Copy link

dracorp commented Nov 9, 2021

@EvilBeaver THX for sharing Maybe someone is interested, I added a function to skip younger build:
Could you say why? What does it give you?

@MichaelKorn
Copy link

@dracorp
The benefits depend heavily on your application, but of course there is a reason why the workspace is not automatically cleaned up immediately after a build.
Furthermore, the workspace can serve as a cache for further builds, at least for the git checkout.
But there are also many good reasons to clean the workspace directly, but then I would rely directly on short-lived agents anyway.

@basilevs
Copy link

@EvilBeaver THX for sharing Maybe someone is interested, I added a function to skip younger build:

    buildAgeDays = (System.currentTimeMillis() - item.getLastBuild().getTimeInMillis()) / (1000*60*60*24)
    if(buildAgeDays < 5 ){
      println(".. job " + jobName + " was recently running, last build: " + item.getLastBuild().getTimestampString())
      continue
    }

This will fail on jobs without builds and probably on disabled jobs.

@mthielen77
Copy link

@basilevs
Copy link

I might have missed a point. Old workspaces are automatically cleaned by Jenkins. Why such a script?

The built-in cleanup is time based, but the cleanup should happen when disk space is used up. Jenkins has no means to schedule jobs based on agents with enough disk space, which causes multiple large workspaces to be allocated on the same agent, leading to build failures. There are also situations, when large jobs are run in a quick succession, making time based retainment useless.

Also, keeping old workspaces is usefull, if agent disk space in underused (for debugging).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment