我们有一个有八个节点的Hudson集群。当特定代码分支不再处于活动状态时,我们会禁用构建作业,但该作业的工作空间仍会占用所有节点上的空间。
我正在寻找一种在所有节点上触发工作区清理的方法。请注意,我不是在寻找“构建前的干净工作空间”解决方案。
答案 0 :(得分:4)
您不需要编写插件。您可以编写一个使用Groovy plugin编写Groovy系统脚本的作业。这项工作会在每晚进行。它将识别禁用的项目并删除其工作区。以下是您的脚本将使用的Hudson Model API链接。在http://<hudson-server>/script
有一个Groovy脚本控制台,它对调试非常有用。
这是一个应该对您有直接好处的代码段。在脚本控制台中运行它并检查输出:
def hi = hudson.model.Hudson.instance
hi.getItems(hudson.model.Job).each {
job ->
println(job.displayName)
println(job.isDisabled())
println(job.workspace)
}
您还可以在this answer中找到有用的代码段。它们指的是Jenkins API,但在这个层面上,我认为Jenkins和Hudson之间没有区别。
<强>更新强>
以下是如何在多个从站上执行此操作:创建在所有从站上运行的多配置作业(也称为“矩阵作业”)。在每个从属服务器上,以下系统Groovy脚本将为您的每个作业提供其工作空间 on slave (以及启用/禁用标志):
def hi = hudson.model.Hudson.instance
def thr = Thread.currentThread()
def build = thr?.executable
def node = build.executor.owner.node
hi.getItems(hudson.model.Job).each {
job ->
println("---------")
println(job.displayName)
println(job.isDisabled())
println(node.getWorkspaceFor(job))
}
当脚本在从属设备上运行时,您可以直接从其中清除工作空间。当然,礼拜空间可能不存在,但这不是问题。请注意,您只编写一次脚本 - Jenkins将在您在矩阵作业中自动指定的所有从站上运行它。
答案 1 :(得分:3)
我尝试过以下脚本,它适用于单节点,
def hi = hudson.model.Hudson.instance
hi.getItems(hudson.model.Job).each {
job ->
if(job.isDisabled())
{
println(job.displayName)
job.doDoWipeOutWorkspace()
}
}
答案 2 :(得分:3)
以下Groovy脚本擦除所有节点上某些作业的工作空间。从“Jenkins主机”/计算机/(主)/脚本
执行在TODO部分中,将作业名称更改为您需要的名称。
import hudson.model.*
// For each job
for (item in Hudson.instance.items)
{
jobName = item.getFullDisplayName()
// check that job is not building
if (!item.isBuilding())
{
// TODO: Modify the following condition to select which jobs to affect
if (jobName == "MyJob")
{
println("Wiping out workspaces of job " + jobName)
customWorkspace = item.getCustomWorkspace()
println("Custom workspace = " + customWorkspace)
for (node in Hudson.getInstance().getNodes())
{
println(" Node: " + node.getDisplayName())
workspacePath = node.getWorkspaceFor(item)
if (workspacePath == null)
{
println(" Could not get workspace path")
}
else
{
if (customWorkspace != null)
{
workspacePath = node.getRootPath().child(customWorkspace)
}
pathAsString = workspacePath.getRemote()
if (workspacePath.exists())
{
workspacePath.deleteRecursive()
println(" Deleted from location " + pathAsString)
}
else
{
println(" Nothing to delete at " + pathAsString)
}
}
}
}
}
else
{
println("Skipping job " + jobName + ", currently building")
}
}
答案 3 :(得分:1)
它有点晚了,但我遇到了同样的问题。我的脚本将检查是否有至少2 GB的空间。如果不是这种情况,节点上的所有工作空间都将被清除以释放空间。
import hudson.FilePath.FileCallable
import hudson.slaves.OfflineCause
for (node in Jenkins.instance.nodes) {
computer = node.toComputer()
if (computer.getChannel() == null) continue
rootPath = node.getRootPath()
size = rootPath.asCallableWith({f, c -> f.getUsableSpace()} as FileCallable).call()
roundedSize = size / (1024 * 1024 * 1024) as int
println("node: " + node.getDisplayName() + ", free space: " + roundedSize + "GB")
if (roundedSize < 2) {
computer.setTemporarilyOffline(true, [toString: {"disk cleanup"}] as OfflineCause)
for (item in Jenkins.instance.items) {
jobName = item.getFullDisplayName()
if (item.isBuilding()) {
println(".. job " + jobName + " is currently running, skipped")
continue
}
println(".. wiping out workspaces of job " + jobName)
workspacePath = node.getWorkspaceFor(item)
if (workspacePath == null) {
println(".... could not get workspace path")
continue
}
println(".... workspace = " + workspacePath)
customWorkspace = item.getCustomWorkspace()
if (customWorkspace != null) {
workspacePath = node.getRootPath().child(customWorkspace)
println(".... custom workspace = " + workspacePath)
}
pathAsString = workspacePath.getRemote()
if (workspacePath.exists()) {
workspacePath.deleteRecursive()
println(".... deleted from location " + pathAsString)
} else {
println(".... nothing to delete at " + pathAsString)
}
}
computer.setTemporarilyOffline(false, null)
}
}
答案 4 :(得分:1)
我最近也想要清理我的jenkins工作区,但稍微扭曲一点:我只想从不再存在的工作中删除工作区。这是因为jenkins在删除作业时没有摆脱工作区,这非常烦人。 我们目前只使用主设备,没有单独的节点。
我在某个地方找到了一个脚本(无法再找到该链接),但为了我们的使用而稍微调整了一下,将它放在一个带有“执行系统Groovy脚本”的jenkins工作中。构建步骤,每天运行:
import hudson.FilePath
import jenkins.model.Jenkins
import hudson.model.Job
def deleteUnusedWorkspace(FilePath root, String path) {
root.list().sort{child->child.name}.each { child ->
String fullName = path + child.name
def item = Jenkins.instance.getItemByFullName(fullName);
println "Checking '$fullName'"
try{
if (item.class.canonicalName == 'com.cloudbees.hudson.plugins.folder.Folder') {
println "-> going deeper into the folder"
deleteUnusedWorkspace(root.child(child.name), "$fullName/")
} else if (item == null) {
// this code is never reached, non-existing projects generate an exception
println "Deleting (no such job): '$fullName'"
child.deleteRecursive()
} else if (item instanceof Job && !item.isBuildable()) {
// don't remove the workspace for disabled jobs!
//println "Deleting (job disabled): '$fullName'"
//child.deleteRecursive()
}
} catch (Exception exc) {
println " Exception happened: " + exc.message
println " So we delete '" + child + "'!"
child.deleteRecursive()
}
}
}
println "Beginning of cleanup script."
// loop over possible slaves
for (node in Jenkins.instance.nodes) {
println "Processing $node.displayName"
def workspaceRoot = node.rootPath.child("workspace");
deleteUnusedWorkspace(workspaceRoot, "")
}
// do the master itself
deleteUnusedWorkspace(Jenkins.instance.rootPath.child("workspace"), "")
println "Script has completed."
虽然可能需要一些个人调整。 显然你应该首先注释掉所有删除语句来运行这个脚本,并确保在进行实际运行之前有备份。
答案 5 :(得分:0)
听起来您正在寻找“禁用构建时删除工作区”解决方案。您可以编写一个Hudson插件来执行此操作。这可能有点过头了。
如果我必须这样做(我不会因为我们没有磁盘空间不足),我会写一个单元脚本来查找hudson目录下的所有已禁用的作业。作业由XML文件表示。然后我会让脚本删除任何匹配的工作区。而且我可能会在cron中设置它,所以它可以每晚或每周运行,也可以在环境中运行。