Skip to content

Instantly share code, notes, and snippets.

@askalee
Last active November 18, 2021 12:50
Show Gist options
  • Save askalee/2148608fb4423d97ded690829daae173 to your computer and use it in GitHub Desktop.
Save askalee/2148608fb4423d97ded690829daae173 to your computer and use it in GitHub Desktop.
Monitor jenkins slave disk space
// https://gist.github.com/askalee/2148608fb4423d97ded690829daae173
// HISTORY:
// * 2017/10/19: show free disk size for all nodes
// * 2017/10/23: auto check nodes labeled with _autoClean
// * 2017/10/26: 1. monitor all nodes instead of only monitor specific nodes with certain label
// 2. catch exceptions
import hudson.model.*;
import hudson.util.*;
import jenkins.model.*;
import hudson.FilePath.FileCallable;
import hudson.slaves.OfflineCause;
import hudson.node_monitors.*;
import static Constatns.*;
def RunUnitTests() {
println("INFO: Running Unit Tests")
def tests = [:]
// define unit tests here
tests["sample test"] = {
assert 1==1
}
// end of define unit tests
tests.each {testName, testScript ->
println("UNITTEST [${testName}]: Run...")
testScript()
println("UNITTEST [${testName}]: Passed")
}
println("INFO: End of Unit Tests, all tests should have passed")
}
RunUnitTests()
if(build.buildVariableResolver.resolve("HandleUnitTests") == "TestOnly"){
println("WARNING: Run tests only, skip running main script")
return 0
}
////// Main Script ///////
class Constatns{
static final MINIMUM_SPACE_IN_G = 10
}
def mapNodeToFreeSize = [:]
def mapDangerousNodeToFreeSize = [:]
def nodesToCheck = Jenkins.instance.nodes
for (node in nodesToCheck) {
println("=== Begin to handle node ${node.name} ===")
try {
computer = node.toComputer()
rootPath = node.getRootPath()
if(rootPath == null){
println("WARNING: Cannot get rootPath on node ${node.name}")
continue
}
println("jenkins folder: ${rootPath}")
size = DiskSpaceMonitor.DESCRIPTOR.get(computer).size
roundedSize = (size / (1024f * 1024f * 1024f)).round(2)
println("node: " + node.getDisplayName() + ", free space: " + roundedSize + "GB")
mapNodeToFreeSize[node.name.toString()] = roundedSize
if (roundedSize < MINIMUM_SPACE_IN_G) {
mapDangerousNodeToFreeSize[node.name.toString()] = roundedSize
}
} catch(e) {
println("ERROR: exception: " + e.toString())
e.printStackTrace()
}
}
Thread.currentThread().executable.setDescription(
GenerateDescription(nodesToCheck, mapNodeToFreeSize, mapDangerousNodeToFreeSize))
return (mapDangerousNodeToFreeSize.size() > 0) ? false : true
//////////////////////////////////////////////
def GenerateDescription(nodesToCheck, mapNodeToFreeSize, mapDangerousNodeToFreeSize) {
def desc = StringBuilder.newInstance()
if(mapDangerousNodeToFreeSize.size() > 0) {
desc << "<h1>Found some dangerous nodes, which have free space lower than ${MINIMUM_SPACE_IN_G}G</h1>"
desc << "Dangerous Nodes:"
desc << "<table border=1>"
mapDangerousNodeToFreeSize.each{node, freeSpace ->
desc << "<tr>"
desc << "<th align='left'>${node}</th>"
desc << "<td align='right'><font color=red>${String.format("%.2f",freeSpace)}G</font></td>"
desc << "</tr>"
}
desc << "</table>"
} else {
desc << "<h1>Great! No dangerous nodes, which have free space lower than ${MINIMUM_SPACE_IN_G}G</h1>"
}
desc << "<br/>Verified nodes:"
nodesToCheck.each{v ->
desc << "<ul>"
desc << "<li>${v.name}: ${mapNodeToFreeSize[v.name]}G</li>"
desc << "</ul>"
}
return desc.toString()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment