Skip to content

Instantly share code, notes, and snippets.

@basilevs
Last active November 17, 2022 18:33
Show Gist options
  • Save basilevs/9645529d4738e8d6b363ac475af6f297 to your computer and use it in GitHub Desktop.
Save basilevs/9645529d4738e8d6b363ac475af6f297 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.*;
import org.jenkinsci.plugins.workflow.job.WorkflowRun
import org.jenkinsci.plugins.workflow.flow.FlowExecution;
import org.jenkinsci.plugins.workflow.graph.FlowGraphWalker;
import org.jenkinsci.plugins.workflow.graph.FlowNode;
import org.jenkinsci.plugins.workflow.graph.StepStartNode;
import org.jenkinsci.plugins.workflow.cps.nodes.StepStartNode;
import org.jenkinsci.plugins.workflow.actions.WorkspaceAction
def MIN_FREE_DISK_SPACE = 10 //GB
boolean shouldSkip(item) {
jobName = item.getFullDisplayName()
if ( !item instanceof Job ||
"${item.class}".contains('Folder') ||
!item.metaClass.respondsTo(item, "isBuilding")) {
return true
}
if (item.isBuilding()) {
println(".. job " + jobName + " is currently running, skipped")
return true
}
return false
}
for (node in Jenkins.instance.nodes) {
computer = node.toComputer()
if (computer.getChannel() == null) {
continue
}
//this should keep jenkins master out of harms way
//change prefix to match your env
name = node.getDisplayName()
if (!name.startsWith("ub") && !name.startsWith("win")) {
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")
if (roundedSize <= MIN_FREE_DISK_SPACE) {
computer.setTemporarilyOffline(true, new hudson.slaves.OfflineCause.ByCLI("disk cleanup"))
println "Set " + node.getDisplayName() + " temporarily offline"
for (item in Jenkins.instance.getAllItems(TopLevelItem)) {
if (shouldSkip(item)) {
continue
}
jobName = item.getFullDisplayName()
workspacePath = node.getWorkspaceFor(item)
if (workspacePath == null) {
continue
}
customWorkspace=""
if (!"${item.class}".contains('Workflow')) {
customWorkspace = item.getCustomWorkspace()
println("Custom workspace " + customWorkspace)
} else {
b = item.getLastBuild()
if(b instanceof WorkflowRun) {
exec = b.getExecution();
if(exec == null) {
continue;
}
FlowGraphWalker w = new FlowGraphWalker(exec);
for (FlowNode n : w) {
if (n instanceof StepStartNode) {
action = n.getAction(WorkspaceAction);
if(action) {
if (action.getNode() != node.getNodeName()) {
continue
}
String workspace = action.getPath().toString();
println("WorkspaceAction: " + workspace)
customWorkspace = workspace
break
}
}
}
} else {
continue
}
}
println("Job " + jobName +", workspace: " + workspacePath + ", custom workspace: " + customWorkspace)
if (customWorkspace != null && !customWorkspace.isEmpty()) {
println("Root path: " + node.getRootPath())
workspacePath = node.getRootPath().child(customWorkspace)
}
pathAsString = workspacePath.getRemote()
println("To delete: " + workspacePath)
if (workspacePath.exists()) {
//uncommend next to actually delete dirs
//workspacePath.deleteRecursive()
println("Deleted " + name + ":" + pathAsString)
}
}
computer.setTemporarilyOffline(false, null)
println "Set " + node.getDisplayName() + " back online"
}
}
@basilevs
Copy link
Author

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