首页 > 解决方案 > 詹金斯管道:等待另一个工作暂停

问题描述

我有几个测试项目(API 测试、UI Selenium 测试等),它们测试同一个应用程序。现在,应用程序的步骤。部署在每个 jenkins 文件中都有重复。

目标是有一个通用的应用程序部署作业,它在服务器上准备应用程序:

我不能在此之后完成构建,因为 Jenkins 将杀死所有创建的进程,包括启动的 Tomcat。我尝试doNoKillMe了 Tomcat 的 cookie,但这导致了与重新启动应用程序和数据库连接相关的其他几个问题。因此,当应用程序准备就绪时,我将input步骤与 ID 放在一起:

node {
    properties([
            parameters([
                    string(name: 'REVISION',
                            defaultValue: '',
                    ),
                    string(name: 'TAG_NAME',
                            defaultValue: ''),
            ]),
    ])
    withEnv(buildEnvVariables()) {
        stage('Checkout') {
        }

        stage('Prepare file system') {
        }

        stage('Prepare database') {
        }

        stage('Builds WAR files') {
        }

        stage('Tomcat deploy') {
            // Delete previous WAR files from Tomcat
            // Copy generated files to tomcat
            sh "$TOMCAT_DIR/bin/startup.sh"
            waitForTokenFileOrFail()
        }
        input(id: 'IsBuilt', 'Application is ready... ')
    }
}

现在,我希望从其他几个特定于测试的jenkins 文件中调用此作业:

node {
    properties([
            parameters([
                    string(name: 'TESTS_SUITE',
                            defaultValue: '',
                    ),
                    string(name: 'OTHER_PARAM',
                            defaultValue: ''),
            ]),
    ])
    withEnv(buildEnvVariables()) {
        stage('Checkout') {
        }

        stage('Stop any running application builds') {
            def jenkinsQueue = Jenkins.instance.queue
            jenkinsQueue.items.findAll { it.task.name.startsWith(contextDeployBuildName) }.each {
                echo "Found pending $contextDeployBuildName job. Cancelling: ${it.getId()}"
                jenkinsQueue.doCancelItem(it.getId())
            }

            Jenkins.instance.getItemByFullName(contextDeployBuildName)
                    .getAllJobs().first().getBuilds()
                    ?.each { build ->
                        if (build.isBuilding()) {
                            try {
                                echo "Found running $contextDeployBuildName job. Stopping: ${build.number}"
                                httpRequest(
                                        httpMode: 'POST',
                                        authentication: 'credentialsID',
                                        url: "${JENKINS_URL}job/$contextDeployBuildName/${build.number}/stop")
                            } catch (any) {
                                println any.message
                            }
                        }
                    }
        }

        stage('Build the app') {
            build(wait: true, job: contextDeployBuildName, parameters: [
                    string(name: 'REVISION', value: env.BRANCH_NAME),
                    string(name: 'TAG_NAME', value: env.TAG_NAME)])

            // How to wait for a specific input/condition here???
        }

        stage('Run tests') {
        }

        stage('Report, cleanup') {
        }
    }
}

我正在使用jenkins build stepwithwait条件,但似乎只能等待工作完成。更改部署作业的状态被忽略(我相信,因为没有触发构建监听器):

currentBuild.rawBuild.@result = hudson.model.Result.SUCCESS

问题:

如何在应用程序部署作业中正确通知特定于测试的作业有关触发输入的信息?是否有解决此类“部署测试”问题的标准方法?

目前,除了管道工具之外,我有两种丑陋的方法来检查状态:

  1. 等待 Tomcat/应用程序文件夹中的某些特定文件
  2. 当触发具有指定 ID 的输入时,可以通过该 ID 访问它的页面,因此我可以 ping 输入的页面,直到它返回 200 状态而不是 404。

标签: tomcatjenkinscontinuous-integrationjenkins-pipelinecloudbees

解决方案


一段历史:几年前,Jenkins 有固定的工作,人们过去常常将这些工作视为构建块,并从另一个触发。这不是很方便,长话短说,管道诞生了。

管道不应该相互触发,因为如果您的两个作业之间存在如此多的依赖关系,其中一个必须等​​待并发出信号,那么将它们视为单个管道的一部分可能会更好。

代码重复是一个问题,但如果您将所有步骤视为更大管道的一部分,则可以处理它。与此相符的东西(从您的代码复制粘贴到声明性管道中):

pipeline {
    agent any
    parameters {
        string(name: 'REVISION', defaultValue: '')
        string(name: 'TAG_NAME', defaultValue: '')
        choice(name: 'TEST_SUITE', choices: ['selenium', 'api', 'etc'])
    }
    stages {
        stage('Checkout') {
        }

        stage('Prepare file system') {
        }

        stage('Prepare database') {
        }

        stage('Builds WAR files') {
        }

        stage('Tomcat deploy') { 
        agent { label "tomcat" } 
        steps { script { 
            sh "$TOMCAT_DIR/bin/startup.sh"
        }}}

        // start testing
        stage('Testing') {
            parallel {
                stage('Selenium') {
                    when { equals expected: "selenium", actual: params.TEST_SUITE }}
                    agent { label "selenium-slave" }
                    steps {
                        echo "Doing selenium tests"
                    }
                }
                stage('API') {
                    when { equals expected: "api", actual: params.TEST_SUITE }}
                    agent { label "api-slave" }
                    steps {
                        echo "Doing api tests"
                    }
                }
            }
        }
        stage('Cleanup') { 
        agent { label "tomcat" } 
        steps { script { 
            sh "$TOMCAT_DIR/bin/shutdown.sh"
        }}}
    }
}

编辑:让你的'start tomcat'和'stop tomcat'落在完全相同的节点上可能是一个问题,但是一些并行化和post { }块也可以解决这个问题。


推荐阅读