如何触发手动清理Hudson工作区

时间:2012-07-09 00:10:43

标签: hudson

我们有一个有八个节点的Hudson集群。当特定代码分支不再处于活动状态时,我们会禁用构建作业,但该作业的工作空间仍会占用所有节点上的空间。

我正在寻找一种在所有节点上触发工作区清理的方法。请注意,我不是在寻找“构建前的干净工作空间”解决方案。

6 个答案:

答案 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中设置它,所以它可以每晚或每周运行,也可以在环境中运行。