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 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 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 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 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 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.

@kumar0608

This comment has been minimized.

Copy link

@kumar0608 kumar0608 commented May 1, 2020

my workspace having some files with root permission, Is there any suggestion on this ?

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