Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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
if (!node.getDisplayName().startsWith("slave-")) {
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()
} 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) {
String workspace = action.getPath().toString();
customWorkspace = workspace
break
}
}
}
}
}
if (customWorkspace != null) {
workspacePath = node.getRootPath().child(customWorkspace)
}
pathAsString = workspacePath.getRemote()
if (workspacePath.exists()) {
//uncommend next to actually delete dirs
//workspacePath.deleteRecursive()
println(" ...deleted " + pathAsString)
}
}
computer.setTemporarilyOffline(false, null)
println "Set " + node.getDisplayName() + " back online"
}
}
@TheNitek

This comment has been minimized.

Copy link

TheNitek commented Mar 5, 2018

Gives me a compilation error. I think the "}" on line 89 needs to be removed.

@TheNitek

This comment has been minimized.

Copy link

TheNitek commented Mar 5, 2018

The script tried to delete my /opt/jenkins on my linux node (which luckily failed due to the permissions) so it doesn't seem safe to run.

@zerogvt

This comment has been minimized.

Copy link
Owner Author

zerogvt commented Mar 14, 2018

  • Fixed syntax error (wrong }). Sorry about that - I removed some printouts before pasting the code and I guess I overdid it.
  • I don't understand how you got the result you describe in your second commend. Jenkins master node is not returned in the nodes array (line 33) as clearly stated in the API. I also tested on a local instance but I couldn't reproduce. Anyhow I added a check (line 40) that should keep jenkins master - out of the way in the unlikely case it is being returned by the call to getNodes().
    Keep in mind that this -being a gist and not a complete program- is only supposed to be a starting point. There might be other assumptions in my code that won't fit your case.
@burnettk

This comment has been minimized.

Copy link

burnettk commented May 14, 2018

i don't think it's about running on master. i added a println of the directory it was trying to delete on an agent, since it was getting "remote file operation failed" and i was curious why, and it said it was trying to delete /opt/jenkins, which is not a workspace dir, but the jenkins root directory on the agent.

@stephan2012

This comment has been minimized.

Copy link

stephan2012 commented May 30, 2018

item.isBuilding() fails if item is a WorkflowMultiBranchProject:

groovy.lang.MissingMethodException: No signature of method: org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject.isBuilding() is applicable for argument types: () values: []
Possible solutions: isBuildable(), isBuildable()
	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 hudson.model.Job$isBuilding.call(Unknown Source)
	at Script1.run(Script1.groovy:25)
	at groovy.lang.GroovyShell.evaluate(GroovyShell.java:585)
	at groovy.lang.GroovyShell.evaluate(GroovyShell.java:623)
	at groovy.lang.GroovyShell.evaluate(GroovyShell.java:594)
	at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SecureGroovyScript.evaluate(SecureGroovyScript.java:343)
	at hudson.plugins.groovy.SystemGroovy.run(SystemGroovy.java:95)
	at hudson.plugins.groovy.SystemGroovy.perform(SystemGroovy.java:59)
	at hudson.tasks.BuildStepMonitor$1.perform(BuildStepMonitor.java:20)
	at hudson.model.AbstractBuild$AbstractBuildExecution.perform(AbstractBuild.java:744)
	at hudson.model.Build$BuildExecution.build(Build.java:206)
	at hudson.model.Build$BuildExecution.doRun(Build.java:163)
	at hudson.model.AbstractBuild$AbstractBuildExecution.run(AbstractBuild.java:504)
	at hudson.model.Run.execute(Run.java:1727)
	at hudson.model.FreeStyleBuild.run(FreeStyleBuild.java:43)
	at hudson.model.ResourceController.execute(ResourceController.java:97)
	at hudson.model.Executor.run(Executor.java:429)

Not sure yet how to handle this best.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.