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)
}
@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