问题:如何在一个options
块中使用NODE_NAME
?
我已经尝试过简单的解决方案,尝试使用env.NODE_NAME
,但是在options
块中,它的结果是null
:
options { lock(resource: "${env.NODE_NAME}") }
Jenkins Pipeline文档解释了这不起作用的原因:
在stage
中,options
指令中的步骤在进入agent
或检查任何when
条件之前被调用。
因此,在此上下文中,它被设置为null
。
接下来,我尝试了各种方法来获取stage { steps {}}
级别的env.NODE_NAME
,并通过一个全局Groovy变量将其传递上去,但是,这似乎不起作用。
在下面的示例Jenkinsfile
中,全局Groovy变量GLOBAL_NODE_NAME
在每个steps
、step
或script
块中的作用就像是一个局部变量。它的作用就像是pipeline { stage { options {} }}
块中的一个全局变量一样。上下文不会上升到全局Groovy脚本级别。
我尝试做的事情:
我想在options
块中使用lockable-resources
插件的lock
语法来限制并发作业。如果有多个作业运行parallel
“Run Tests
“阶段,Jenkins代理节点上的所有RAM都会被消耗。因此,我尝试锁定每个节点的资源来限制此特定节点上的并发作业。
我使用的最小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
: - x1米25英寸1x
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
:
***注:**在options
块中,echo
、println
不可用......但我们可以在https://<jenkins-host-here>/lockable-resources/
页上的资源名称中看到输出: GLOBAL_NODE_NAME
被设置为“GLOBAL
“,所以stage
=〉step
赋值没有工作!
*可锁定资源显示resource
的值仍设置为GLOBAL
!
- 并行阶段:
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)
EDIT:这是最终的工作解决方案
多亏了@AdamSmith的answer,它让我找到了正确的方向。下面是最终成功的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
1条答案
按热度按时间niwlg2el1#
你不能,但是由于
lock
在steps
块中 * 也 * 可用,你可以这样处理它。由于这些事情的性质,你可能不得不在这里使用script
退出窗口来继续并行(抱歉)