Skip to content

Instantly share code, notes, and snippets.

@antonpiatek
Forked from rb2k/gist:8372402
Last active July 21, 2023 10:56
Show Gist options
  • Save antonpiatek/c74991f7ec54126fc91dd66a290d7520 to your computer and use it in GitHub Desktop.
Save antonpiatek/c74991f7ec54126fc91dd66a290d7520 to your computer and use it in GitHub Desktop.
A jenkins script to clean up workspaces on slaves
// find old workspace folders on any node (master/slave)
// currently only look for deleted branches of multibranch (pipeline?) jobs, and remove them
// also finds builds older than 90 days. Set flags below to true to actually do deletes
import hudson.model.*;
import hudson.util.*;
import jenkins.model.*;
import hudson.FilePath;
import hudson.FilePath.FileCallable;
import hudson.slaves.OfflineCause;
import hudson.node_monitors.*;
import org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject;
import org.jenkinsci.plugins.workflow.job.WorkflowJob;
//Configurabke options
deleteStaleMultiBranchJobs = false
deleteOldJobs = false
jobMaxAge = 90
tick = "\u2713"
trash = "\u267B"
jobMap = Jenkins.instance.itemMap
def padJob(def jobname){
return "${jobname}".padRight(50,".")
}
def deleteWorkflowBranchJob(def subdir){
if(deleteStaleMultiBranchJobs){
subdir.deleteRecursive()
return "${trash} removed"
}else{
return "${trash} DELETE DISABLED, change 'deleteStaleMultiBranchJobs' to enable"
}
}
def lookupJob(def lookup, def parent){
//some jobs have workspaces ending in @tmp, ignore the @tmp part
if(lookup ==~ /.*@tmp$/){
lookup = lookup -~ /@tmp$/
}
if(lookup ==~ /.*@script$/){
lookup = lookup -~ /@script$/
}
if(lookup ==~ /.*@\d$/){
lookup = lookup -~ /@\d$/
}
def job;
if(parent != null){
job = parent.getItem(lookup)
}else{
job = jobMap[lookup]
}
return job;
}
def purgeAncientJob(def job, def dir){
//TODO: Should we have a list of protected job names? i.e. master or releases/*
//TODO: job.isBuilding() ?
//TODO factor out an use for any build type
def buildAgeSec = (System.currentTimeMillis() - job.getLastBuild().getTimeInMillis()).intdiv(1000)
def buildAgeDays = buildAgeSec.intdiv(3600).intdiv(24)
if(buildAgeDays > jobMaxAge ){
if(deleteOldJobs){
println padJob(".... $dir.name")+" ${trash} removed"
dir.deleteRecursive()
}else{
println padJob(".... $dir.name")+" ${trash} DELETE DISABLED, change 'deleteOldJobs' to delete ${buildAgeDays} days old build"
}
} else{
println padJob(".... $dir.name")+" ${tick} ${job.getLastBuild().getTimestampString()} "
}
}
def cleanupNode(def ws){
for(dir in ws.listDirectories()){
def job = lookupJob(dir.name,null)
if(job != null){
if(job instanceof WorkflowMultiBranchProject){
println padJob(".. $dir.name")+" existing multibranch pipeline job"
for(subdir in dir.listDirectories()){
def subjob = lookupJob(subdir.name, job)
if(subjob != null){
purgeAncientJob(subjob, subdir)
}else{
println padJob(".... $subdir.name")+" "+deleteWorkflowBranchJob(subdir)
}
}
}else if(job instanceof WorkflowJob){
println padJob(".. $dir.name")+" existing pipeline job ${tick}"
}else{
println padJob(".. $dir.name")+" job of type ${job}"
}
}else{
println padJob(".. $dir.name")+" UNKNOWN JOB, not automatically deleting"
}
println()
}
}
def processNode(def node){
def computer = node.toComputer()
if (computer == null || computer.channel == null){
println "[$node.displayName] OFFLINE"
}else{
def rootPath = node.getRootPath()
def diskMon = DiskSpaceMonitor.DESCRIPTOR.get(computer)
if(diskMon == null){
println "[$node.displayName] CAN'T CALCULATE SIZE"
}else{
def size = DiskSpaceMonitor.DESCRIPTOR.get(computer).size
def roundedSize = size.div(1024 * 1024 * 1024) as int
println "[$node.displayName] $node.workspaceRoot free space: ${roundedSize} GB"
}
try{
//computer.setTemporarilyOffline(true, new hudson.slaves.OfflineCause.ByCLI("disk cleanup"))
def ws = node.getWorkspaceRoot()
cleanupNode(ws)
}finally{
//computer.setTemporarilyOffline(false, null)
}
}
println("\n")
}
def main(){
def nodes = Jenkins.instance.nodes
for (node in nodes) {
processNode(node)
}
println "[MASTER]"
cleanupNode(new FilePath(Jenkins.instance.rootPath,'workspace'))
}
println()
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment