问:如何在NODE_NAME
块中使用options
?
我尝试过简单地尝试使用env.NODE_NAME
的天真解决方案,但这会在options
块中计算为null
:
options { lock(resource: "${env.NODE_NAME}") }
Jenkins管道文档解释了为什么这不起作用:
在
stage
中,在输入agent
或检查任何when
条件之前调用options
指令中的步骤。
因此,在这个上下文中,它被设置为null
。
接下来,我尝试了各种方法来获得env.NODE_NAME
级别的stage { steps {}}
,并通过一个全局Groovy变量传递它。然而,这似乎不起作用。
在下面的示例Jenkinsfile
中,全局Groovy变量GLOBAL_NODE_NAME
的作用就好像它是每个steps
、step
或script
块中的局部变量一样。同时,它的作用就好像它是pipeline { stage { options {} }}
块中的一个全局变量。节点“重量级执行器”上下文中设置的值不会冒泡到全局Groovy脚本级别。
我想做的是:
我想在一个lockable-resources
块中使用lock
插件的lock
语法来限制并发作业。如果多个作业运行parallel
"Run Tests
“阶段,那么所有RAM都会在Jenkins代理节点上使用。因此,我试图锁定每个节点的资源,以限制这个特定节点上的并发作业。
我使用的最小Jenkinsfile
如下所示:
String GLOBAL_NODE_NAME = 'GLOBAL'
pipeline {
agent { label 'ec2-node' }
stages {
stage('Get Node Name') {
steps {
script {
println("env.NODE_NAME='${env.NODE_NAME}'")
GLOBAL_NODE_NAME = NODE_NAME
println("GLOBAL_NODE_NAME='${GLOBAL_NODE_NAME}'")
}
}
}
stage('Build') {
steps {
script {
println("DEBUG Interpolation GLOBAL_NODE_NAME='${GLOBAL_NODE_NAME}'")
println("DEBUG Raw Groovy Variable GLOBAL_NODE_NAME='" + GLOBAL_NODE_NAME + "'")
}
sh "echo Shell string Interpolation GLOBAL_NODE_NAME='${GLOBAL_NODE_NAME}'"
// Do build steps here
}
}
stage('Run Tests') {
// Inverse order LIFO
options {
// Get NODE_NAME from the currentBuild b/c lightweight executor returns 'null'
lock(inversePrecedence: true, resource: "${GLOBAL_NODE_NAME}")
}
parallel {
stage('Unit Tests') {
steps {
echo "Inside Steps block: GLOBAL_NODE_NAME='${GLOBAL_NODE_NAME}'"
script {
println("DEBUG Interpolation GLOBAL_NODE_NAME='${GLOBAL_NODE_NAME}'")
println("DEBUG Raw Groovy Variable GLOBAL_NODE_NAME='" + GLOBAL_NODE_NAME + "'")
}
sh "echo Shell string Interpolation GLOBAL_NODE_NAME='${GLOBAL_NODE_NAME}'"
// Do Unit Tests
}
}
stage('Integration Tests') {
steps {
sh 'echo this so example Jenkinsfile is valid'
// Do Integration Tests
}
}
} // end parallel
} // end Run Tests
} // end stages
} // end pipeline
上述示例作业的输出:
Get Node Name
- `env.NODE_NAME='EC2 (EC2-Jenkins) - Pipeline Builder (i-feeb1ec0de5caff01d)'`
- `GLOBAL_NODE_NAME='EC2 (EC2-Jenkins) - Pipeline Builder (i-feeb1ec0de5caff01d)'`
Build
- `DEBUG Interpolation GLOBAL_NODE_NAME='EC2 (EC2-Jenkins) - Pipeline Builder (i-feeb1ec0de5caff01d)'`
- `DEBUG Raw Groovy Variable GLOBAL_NODE_NAME='EC2 (EC2-Jenkins) - Pipeline Builder (i-feeb1ec0de5caff01d)'`
- echo Shell string Interpolation GLOBAL\_NODE\_NAME=EC2 (EC2-Jenkins) - Pipeline Builder (i-feeb1ec0de5caff01d) Shell string Interpolation GLOBAL\_NODE\_NAME=EC2 (EC2-Jenkins) - Pipeline Builder (i-feeb1ec0de5caff01d)
Run Tests
- **Note:** Inside `options` block, `echo`, `println`, are not available... but we can see the output in the resource's name on the `https://<jenkins-host-here>/lockable-resources/` page:
- `GLOBAL_NODE_NAME` is set to "`GLOBAL`", so the `stage` => `step` assignment did **not** work!
-
- **Lockable Resources shows that the value of** **`resource`** **is still set to** **`GLOBAL`****!**
- Parallel Stage: `Unit Tests`
- `Inside Steps block: GLOBAL_NODE_NAME='EC2 (EC2-Jenkins) - Pipeline Builder (i-feeb1ec0de5caff01d)'`
- `DEBUG Interpolation GLOBAL_NODE_NAME='EC2 (EC2-Jenkins) - Pipeline Builder (i-feeb1ec0de5caff01d)'`
- `DEBUG Raw Groovy Variable GLOBAL_NODE_NAME='EC2 (EC2-Jenkins) - Pipeline Builder (i-feeb1ec0de5caff01d)'`
- + echo Shell string Interpolation GLOBAL\_NODE\_NAME=EC2 (EC2-Jenkins) - Pipeline Builder (i-feeb1ec0de5caff01d) Shell string Interpolation GLOBAL\_NODE\_NAME=EC2 (EC2-Jenkins) - Pipeline Builder (i-feeb1ec0de5caff01d)
编辑:这是最后的工作解决方案
多亏了@AdamSmith的回答,它让我开始朝着正确的方向前进。下面是工作的最终Jenkinsfile
结构的框架:
/* groovylint-disable DuplicateStringLiteral */
/* groovylint-disable-next-line CompileStatic */
String debugBegin = '============================== DEBUG ENV =============================='
String debugEnd = '============================== END DEBUG =============================='
/* groovylint-disable NestedBlockDepth */
/* groovylint-disable-next-line CompileStatic */
pipeline {
agent { label 'ec2-node' }
stages {
stage('Build') {
steps {
script {
// Evaluates in 'heavyweight' executor context
println("Running on env.NODE_NAME='${env.NODE_NAME}'") // env.NODE_NAME works here
}
// Do build steps here
}
}
stage('Run Tests') {
options {
/*
Note: Cannot get NODE_NAME from this context!
options is evaluated inside 'lightweight' executor, so currentBuild returns 'null'
and any other method trying to pass env.NODE_NAME, or
NODE_NAME up from the node / 'heavyweight' executor context did not work!
lock(inversePrecedence: true, resource: "cannot-get-node-name") // Anything I tried here did not work!
This context executes on jenkins master, and I could not find a way to pass the value back from a node
*/
timeout(time: 15, unit: 'MINUTES')
}
steps {
// Inverse order LIFO
// lock NODE_NAME b/c parallel tests are RAM intensive
lock(inversePrecedence: true, resource: "${NODE_NAME}") {
script { // hack so parallel syntax is made available here
parallel Test: { // map: {} syntax to pass to scripted-pipeline 'parallel'
stage('Test') {
try { // Switched from post { always {}} to => try {} finally {} here
// because syntax did not work otherwise
echo "Inside Steps block: NODE_NAME='${NODE_NAME}'"
println("DEBUG Interpolation NODE_NAME='${NODE_NAME}'")
println("DEBUG Raw Groovy Variable NODE_NAME='" + NODE_NAME + "'")
sh "echo Shell string Interpolation GLOBAL_NODE_NAME='${NODE_NAME}'"
echo "${debugBegin}"
sh 'env' // STAGE_NAME is now 'Test'
echo "${debugEnd}"
sh 'make test'
echo 'Tests Succeeded!'
}
finally {
junit '**/path/to/test-reports/*.xml'
sh 'make cleanup'
}
}
},
IntegrationTests: {
stage('Integration Tests') {
try {
echo "${debugBegin}"
sh 'env' // STAGE_NAME is now 'Integration Tests'
echo "${debugEnd}"
sh 'make integration'
echo 'Integration Tests Succeeded!'
}
finally {
sh 'make cleanup'
}
}
} // end parallel map
} // end script
} // end lock NODE_NAME
} // end steps
} // end stage Run Tests
} // end stages
} // end pipeline
发布于 2022-05-05 06:01:55
您不能这样做,但是由于lock
也可以在steps
块中使用,所以您可以这样处理它。由于这些事情的性质,您可能需要在这里使用一个script
转义程序来继续并行(对不起)
stage('Run Tests') {
steps {
// Inverse order LIFO
lock(inversePrecedence: true, resource: "${NODE_NAME}") {
script {
parallel [
'Unit Tests': {
echo "Inside Steps block: NODE_NAME='${NODE_NAME}'"
println("DEBUG Interpolation NODE_NAME='${NODE_NAME}'")
println("DEBUG Raw Groovy Variable NODE_NAME='" + NODE_NAME+ "'")
sh "echo Shell string Interpolation GLOBAL_NODE_NAME='${GLOBAL_NODE_NAME}'"
},
'Integration Tests': {
sh 'echo this so example Jenkinsfile is valid'
}
]
} // end script
} // end lock
} // end steps
} // end stage 'Run Tests'
https://stackoverflow.com/questions/72122472
复制相似问题