如何从并行子作业复制工件

Dan*_*n N 5 jenkins jenkins-plugins jenkins-pipeline

我正在使用 Jenkins 来自动化并行 JMeter 测试。这是设置为两个独立的 Jenkins 管道作业,即父作业和子作业。

\n\n

子作业采用一系列参数并对目标服务执行 JMeter 测试。这是有效的,并且在每个版本上归档四个 CSV 和一个 XML 文件。

\n\n

父作业在不同节点上并行执行子作业多次。目前,它在测试中执行两次,但最终旨在一次生成 10 或 20 个子作业。并行执行有效,每次执行父作业时,子作业都会记录两个构建,并存档它们的工件。

\n\n

问题是如何配置复制工件插件以从子作业中检索工件,以便将它们存档在父作业上。

\n\n
    \n
  1. 我尝试过 buildParameter 选项(CC_DGN_Test 是子作业的名称)。我在子作业中创建了一个名为ParentBuildTag、类型为 的参数Build selector for Copy Artifact。复选框Permission to Copy Artifact被选中,字段Projects to allow copy artifacts设置为*
  2. \n
\n\n
post {\n    always {\n        script {\n            print "buildParameter(\'${BUILD_TAG}\') == " + buildParameter("${BUILD_TAG}")\n            copyArtifacts optional: false, projectName: \'CC_DGN_Test\', selector: buildParameter("${BUILD_TAG}")\n            archiveArtifacts "*.xml"\n        }\n        cleanWs()\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

构建参数被填充到子作业中,如下所示:

\n\n
stage(\'Node 2\') {\n    agent { node { label \'PIPELINE\' } }\n    steps {\n        script {\n            node2 = build job: \'CC_DGN_Test\',\n                parameters: [\n                    string(name: \'dummy\', value: "2"),\n                    string(name: \'ParentBuildTag\', value: "${BUILD_TAG}"),\n                    string(name: \'Labels\', value: "JMETER"),\n                    ...additional parameters snipped...\n                ]\n        }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

控制台日志显示错误:

\n\n
Error when executing always post condition:\nhudson.AbortException: Unable to find a build for artifact copy from: CC_DGN_Test\n    at hudson.plugins.copyartifact.CopyArtifact.perform(CopyArtifact.java:412)\n    at org.jenkinsci.plugins.workflow.steps.CoreStep$Execution.run(CoreStep.java:80)\n    at org.jenkinsci.plugins.workflow.steps.CoreStep$Execution.run(CoreStep.java:67)\n    at org.jenkinsci.plugins.workflow.steps.SynchronousNonBlockingStepExecution.lambda$start$0(SynchronousNonBlockingStepExecution.java:47)\n    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)\n    at java.util.concurrent.FutureTask.run(FutureTask.java:266)\n    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)\n    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)\n    at java.lang.Thread.run(Thread.java:748)\n
Run Code Online (Sandbox Code Playgroud)\n\n

没有任何内容被复制到父级。构建标记正确打印到控制台日志(来自 post{} 中的打印语句)。

\n\n
08:18:52 buildParameter(\'jenkins-CC_DGN_TrickleTest-45\') == @buildParameter(<anonymous>=jenkins-CC_DGN_TrickleTest-45)\n
Run Code Online (Sandbox Code Playgroud)\n\n

这种方法看起来很有希望,但我认为存在语法问题...我想我应该告诉 copyArtifacts 插件使用 ParentBuildTag 参数,其中值为“jenkins-CC_DGN_TrickleTest-45”,但我没有找到了一个描述语法的示例。

\n\n
    \n
  1. 我尝试过为子作业使用特定的内部版本号。
  2. \n
\n\n
stage(\'Node 2\') {\n    agent { node { label \'PIPELINE\' } }\n    steps {\n        script {\n            node2 = build job: \'CC_DGN_Test\',\n                parameters: [\n                    string(name: \'dummy\', value: "2"),\n                    string(name: \'ParentBuildTag\', value: "${BUILD_TAG}"),\n                    string(name: \'Labels\', value: "JMETER"),\n                    ...additional parameters snipped...\n                ]\n            print "Build number (node 2) = " + node2.number //prints build number to console e.g. "Build number (node 2) = 102"\n            copyArtifacts optional: false, filter: \'*.xml, *.csv\', fingerprintArtifacts: true, projectName: \'CC_DGN_Test\', selector: specific(node2.number)\n        }\n    }\n}\n\n
Run Code Online (Sandbox Code Playgroud)\n\n

内部版本号已正确打印到控制台日志中,但不会记录任何错误,也不会复制任何内容。

\n\n
    \n
  1. 我已经尝试了 buildParameter 方法的替代语法,但不起作用。
  2. \n
\n\n
properties([parameters([\n    [$class: \'BuildSelectorParameter\',\n    defaultSelector: upstream(fallbackToLastSuccessful: true),\n    description: \'\',\n    name: \'ParentBuildTag\']])\n])\ncopyArtifacts(\n    projectName: \'CC_DGN_Test\',\n    selector: [\n        class: \'ParameterizedBuildSelector\', \n        parameterName: \'ParentBuildTag\'\n    ]\n);\n
Run Code Online (Sandbox Code Playgroud)\n\n

再次,我怀疑我需要告诉它 ParentBuildTag 使用什么值,但我借用的语法示例没有显示如何做到这一点。“上游...”部分只是我从示例中复制的内容,不是我认为我需要的内容,但包含在我的测试中似乎无害。

\n\n
    \n
  1. 我尝试在节点阶段的“构建作业”命令之后进行隐藏,并在后期阶段取消隐藏。这些导致在构建作业命令之后的 stash 命令出现错误(“14:00:19 在分支节点 1 中失败”),并在后期阶段的 unstash 命令出现错误(“错误:stash \xe2 中没有包含文件” \x80\x98node1xml\xe2\x80\x99")。
  2. \n
\n\n
stash includes: \'*.xml\', name: \'node1xml\'\n
Run Code Online (Sandbox Code Playgroud)\n\n
unstash \'node1xml\'\n
Run Code Online (Sandbox Code Playgroud)\n\n
    \n
  1. 我尝试将子作业的最低要求部分移至父作业中,而不调用子作业。只要我以不同的方式命名它们,它就会存储一些工件(如果不对底层 JMeter 脚本进行重大更改,则无法更改某些工件),但我宁愿不必将变量传递给 JMeter脚本根据 Jenkins 构建参数修改文件名。这对我来说耦合性太大,而且我喜欢为每个子作业都有一个单独的构建记录。
  2. \n
\n\n

以下是当前的父作业配置,为简洁起见,进行了一些剪裁:

\n\n
pipeline {\n    agent { node { label \'PIPELINE\' } }\n    options {\n        timeout(time: 1, unit: \'HOURS\')\n        buildDiscarder(logRotator(numToKeepStr: \'100\'))\n        timestamps()\n    }\n    environment {\n        node1 = ""\n        node2 = ""\n    }\n\n    stages {\n        stage(\'Clean Up\') {\n            steps {\n                cleanWs()\n            }\n        }\n\n        stage(\'Test\') {\n            parallel {\n                stage(\'Node 1\') {\n                    agent { node { label \'PIPELINE\' } }\n                    steps {\n                        script {\n                            node1 = build job: \'CC_DGN_Test\',\n                                parameters: [\n                                    string(name: \'dummy\', value: "1"),\n                                    string(name: \'ParentBuildTag\', value: "${BUILD_TAG}"),\n                                    string(name: \'Labels\', value: "JMETER"),\n                                    ...additional parameters snipped...\n                                ]\n                        }\n                    }\n                }\n\n                stage(\'Node 2\') {\n                    agent { node { label \'PIPELINE\' } }\n                    steps {\n                        script {\n                            node2 = build job: \'CC_DGN_Test\',\n                                parameters: [\n                                    string(name: \'dummy\', value: "2"),\n                                    string(name: \'ParentBuildTag\', value: "${BUILD_TAG}"),\n                                    string(name: \'Labels\', value: "JMETER"),\n                                    ...additional parameters snipped...\n                                ]\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    post {\n        always {\n            script {\n                copyArtifacts optional: false, projectName: \'CC_DGN_Test\', selector: buildParameter("${BUILD_TAG}")\n                archiveArtifacts "*.xml"\n            }\n            cleanWs()\n        }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

我的目标是根据当前配置,父作业在作业完成后总共包含 8 个 CSV 和 2 个 XML,但当前父作业未存档任何内容。copyArtifact 语法哪里出了问题?

\n

Jom*_*n68 2

你的第2点方法是正确的。您只需要转换node2.number为字符串:

selector: specific("${node2.number}")
Run Code Online (Sandbox Code Playgroud)

您还可以在方法中调用子作业。这是一个示例脚本:

selector: specific("${node2.number}")
Run Code Online (Sandbox Code Playgroud)

在此示例中,子作业都是相同的 Jenkins 作业。父作业将不同的参数传递给每个作业。

子作业生成的报告文件将复制到父作业的 rootReportDir 中。每个子作业的 rootReportDir 应该是唯一的,以便每个报告在存档到父作业时都有唯一的路径。