【问题标题】:How to Inject Stages or steps in Jenkins pipeline如何在 Jenkins 管道中注入阶段或步骤
【发布时间】:2019-10-24 08:37:09
【问题描述】:

这个 python eval 的输出看起来可能是 jenkins 管道中的阶段

 $ python3 -c 'print("\n".join(["stage({val}) {{ do something with {val} }}".format(val=i) for i in range(3)]))'
stage(0) { do something with 0 }
stage(1) { do something with 1 }
stage(2) { do something with 2 }

jenkins 是否可以使用这样的输出来创建管道中的步骤或阶段,以便正在运行的 python 脚本能够更新 jenkins?这样做的目的是让 Blue Ocean 管道有一个阶段点,该阶段点由运行单独作业的外部脚本制作。

详细说明这个例子......如果这个demo.py脚本在一个阶段输出正常运行时间

#!/bin/env python3.6
import subprocess, time

def uptime():
    return (subprocess.run('uptime', stdout=subprocess.PIPE, encoding='utf8')).stdout.strip()

for i in range(3):
    print("stage({val}) {{\n    echo \"{output}\" \n}}".format(val=i, output=uptime()))
    time.sleep(1)

在 jenkins 管道中的设置位置

node {
    stage("start demo"){
        sh "/tmp/demo.py"

    }
}

因为这个演示只是输出文本,并没有在蓝海中创建任何阶段

[Pipeline] sh
+ /tmp/demo.py
stage(0) {
    echo "03:17:16 up 182 days, 12:17,  8 users,  load average: 0.00, 0.03, 0.05" 
}
stage(1) {
    echo "03:17:17 up 182 days, 12:17,  8 users,  load average: 0.00, 0.03, 0.05" 
}
stage(2) {
    echo "03:17:18 up 182 days, 12:17,  8 users,  load average: 0.00, 0.03, 0.05" 
}

再次强调,让 Blue Ocean 管道有一个带有日志的阶段点

【问题讨论】:

    标签: jenkins jenkins-pipeline


    【解决方案1】:

    由于 Jenkins 将您的 Groovy 脚本转换为 Java,对其进行编译并然后执行结果,因此使用外部程序生成更多 Groovy 来执行将非常困难,因为额外的 groovy 代码会需要转换。但是生成的代码是运行的结果,也就是说转换已经完成了。

    相反,您可能希望在 Groovy 中以编程方式构建您的阶段。

    
    some_array = ["/tmp/demo.py", "sleep 10", "uptime"] 
    
    def getBuilders()
    {
        def builders = [:]
    
        some_array.eachWithIndex { it, index ->
            // name the stage
            def name = 'Stage #' + (index + 1)
            builders[name] = {
                stage (name) {
                    def my_label = "jenkins_label" // can choose programmatically if needed
                    node(my_label) {
                            try {
                                doSomething(it)
                            }
                            catch (err) { println "Failed to run ${it}"; throw err  }
                            finally {  }
                        }
                }
            }
        };
        return builders
    }
    
    def doSomething(something) {
        sh "${something}"
    }
    

    稍后在您的主管道中

            stage('Do it all') {
                steps {
                    script {
                        def builders = getBuilders()
                        parallel builders
                    }
                }
    

    这将运行三个并行阶段,其中一个运行/tmp/demo.py,第二个运行sleep 10,第三个运行uptime

    【讨论】:

    • 您的示例很有趣,但它只有在打开外部脚本的管道时才能工作。因此,如果 doSomething 在哪里创建一个阶段,因为它从管道获得了消息。你知道这是否可能吗?
    • 恐怕我不明白你的问题。你在说什么“管道”?
    • 您可以调用外部程序并使用def to_do = sh (script: "1.sh", returnStdout: true).trim() 读取其输出,然后将其作为doSomething(to_do) 传递。所以如果1.sh里面有echo sleep 90,这将被传递并稍后被调用。
    【解决方案2】:

    你可以计算一个表达式然后调用它。

    node(''){
     Closure x = evaluate("{it -> evaluate(it)}" )
     x(" stage('test'){ script { echo 'hi'}}")
    }
    

    【讨论】:

    • evaluate 是新事物,但它如何将外部脚本输出作为其运行?
    • 我假设,您可以使用脚本的输出初始化一个变量,然后调用闭包。
    • 我想我需要更多帮助。 python(或其他)脚本正在服务器上运行,并且需要在完成一个步骤时向 jenkins 发送状态。然后它应该能够将其作为管道中的一个步骤注入并继续执行另一个任务,然后将其更新为一个新步骤。那么评估是如何发生的呢?
    最近更新 更多