天天看点

jenkins中pipeline发送http请求

前提:第一次接触pipeline,完全是边查边写,有些艰难,所以写一下,备忘

1、需求

     pipeline中,编译打包的流程已经完成了,现在需要将打好的包(制品),上传到产品发布系统,产品发布系统没有直接提供上传的目录,而是给了三个接口

1)get_token:发送secret_str(RSA公钥加密),获取token;

2)upload_file:发送token以及文件,获取返回值中的file_id;

3)software_info:发送token以及file_id,最终发布成功

2、发送Http请求

1、其中第一个GET请求,第三个POST请求都可以在网上查到

https://blog.csdn.net/banche163/article/details/104548200

使用HttpRequest,需要先安装HttpRequest插件:jenkins---系统管理---插件管理---可选插件---搜索:“HTTP Request Plugin”---安装(不用重启jenkins也能使用)

2、POST请求上传文件,网上找不到资料,各种尝试也没成功

1)网上有说用HttpBuilder,但是我照着写,却报错https://blog.csdn.net/berdy/article/details/7726936、https://http-builder-ng.github.io/http-builder-ng/asciidoc/html5/

@Grab报错
//@Grab(group='org.codehaus.groovy.modules.http-builder', module='http-builder', version='0.7' )
//import groovyx.net.http.HTTPBuilder
           

2)最终用命令实现的

def response = sh returnStdout: true, script: """curl http://ip:port/testController/upload_file -F "[email protected]${filePath}" -F "sys_id=${sys_id}" -F 'token=${token}' """
           

刚开始直接使用sh命令,由于对语法不熟,为了获取curl命令的返回值还折腾了很久,后来同事帮忙才知道直接可以获取返回值!

设置returnStdout: true 就可获取返回值

不靠谱的方式如下:

def proc = """${env.WORKSPACE}/ci/publish/publish_upload.sh ${token}""".execute()
  proc.consumeProcessOutput(sout, serr)
  proc.waitForOrkill(9000)  ##这个方法总导致失败
  println "out> $sout"
           

注释:publish_upload.sh文件中 就只有一句话“curl http://ip:port/…………”

3、脚本中涉及到加密函数、解析json函数,需要在pipeline代码块之外,写个方法 加@NonCPS注解(原因不清楚)

4、如果都使用curl命令,其实postman可以直接导出shell脚本,这里只上传文件的接口使用了curl命令

postman测试接口成功后,可以直接点击“Code”---选择语言 

jenkins中pipeline发送http请求

5、脚本如下:

import javax.crypto.Cipher
import java.security.KeyFactory
import java.security.PublicKey
import java.security.spec.X509EncodedKeySpec
import groovy.json.JsonSlurperClassic
import java.util.Base64;
import java.util.Base64.Decoder;

@NonCPS
def jsonParse(def json) {
    new groovy.json.JsonSlurperClassic().parseText(json)
}

@NonCPS
def getSecretStr(def sysName){
    //RSA最大加密明文大小
    int MAX_ENCRYPT_BLOCK = 117;
    //secret_str 参数规范: DataEcho+时间戳
    String inputText = sysName + "-" +System.currentTimeMillis();
    String publicKeyStr = "秘钥串";
    //获取公钥
    byte[] keyBytes =(Base64.getMimeDecoder()).decode(publicKeyStr);
    X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    PublicKey publicKey = keyFactory.generatePublic(keySpec);

    //加密
    byte[] plainText=inputText.getBytes();
    Cipher cipher = Cipher.getInstance("RSA");
    cipher.init(Cipher.ENCRYPT_MODE, publicKey);
    int inputLen = plainText.length;
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    int offSet = 0;
    int i = 0;
    byte[] cache;
    while (inputLen - offSet > 0) {
        if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
            cache = cipher.doFinal(plainText, offSet, MAX_ENCRYPT_BLOCK);
        } else {
            cache = cipher.doFinal(plainText, offSet, inputLen - offSet);
        }
        out.write(cache, 0, cache.length);
        i++;
        offSet = i * MAX_ENCRYPT_BLOCK;
    }
    byte[] encryptText = out.toByteArray();
    out.close();

    //Base64编码
    String secret_str = new String((Base64.getMimeEncoder()).encode(encryptText));
    return secret_str

}

pipeline {

    agent {
        label 'master'
    }

    options {
        // 只保存最近20条构建
        buildDiscarder(logRotator(numToKeepStr: '20'))
    }

    parameters {
        // 是否构建制品包
        booleanParam(name: 'generated_console_products', defaultValue: false, description: '是否生成制品')
    }

    stages {

        stage(...){
            ...其他步骤
        }

  //调用接口 上传console包至产品发布系统
        stage('上传产品发布系统') {
            steps {
                script {

                    if (generated_console_products) { //用户选择生成console制品

                        def sys_id = "Test"
                        def basic_name = "Test"
                        def version = 1.2.3
                        def svn_address = "https://ip/test/src/Test/code/trunk/test"
                        def new_function_desc = "new function desc 0508"
                        def fix_bug_desc = "fix bug desc 0508"
                        def test_report = "test repoet 0508"

                        //一、获取token (Get请求 http://ip:port/AutoPublishController/get_token?secret_str=参数)
                        // 参数:secret_str ( 非对称加密(sys_id-时间戳,传递时请使用Base64转码)、必传)
                        //返回值:token

                        //1、1生成secret_str
                        def secret_str = URLEncoder.encode(getSecretStr("Test"), "UTF-8");
                        def response1 = httpRequest contentType: 'APPLICATION_JSON',
                                httpMode: "GET",
                                url: "http://ip:port/AutoPublishController/get_token?secret_str=${secret_str}"
                        println response1.status
                        println response1.content

                        def states = jsonParse(response1.content)
                        def token = states['token']
                        println "token:" + token

                        if (response1.content != null && 200 == states['code']) {
                            println "获取token成功"

                            //二、上传压缩包 (post请求 http://ip:port/AutoPublishController/upload_file?token=参数1&sys_id=参数2 file 参数3)
                            //参数1:sys_id (系统id,参考固定参数说明、必传)
                            //参数2:token (票据(系统返回的内容)、必传)
                            //参数3:file (文件流 必传)
                            //返回值:file_id(系统返回的文件id)


                            def filePath = "/data/jenkins/workspace/TestA/package/boot/package/1.3_boot/distr/server.tar.gz"
                            def response2 = sh returnStdout: true, script: """curl http://ip:port/AutoPublishController/upload_file -F "[email protected]${
                                filePath
                            }" -F "sys_id=${sys_id}" -F 'token=${token}' """

                            println "response2" + response2
                            states = jsonParse(response2)

                            if (response2 != null && 200 == states['code']) {
                                println "上传文件成功"
                                def file_id = states['file_id']
                                println file_id
                                //三、发布信息  (post请求 http://ip:port/AutoPublishController/software_info/)
                                //参数1:sys_id
                                //参数2:token
                                //参数3:basic_name (用于关联产品、必传)
                                //参数4:version (版本 必传)
                                //参数5:new_function_desc (新功能描述信息,可在svn提交记录中抓取 暂时非必传)
                                //参数6:fix_bug_desc(修复问题描述 可在svn提交记录中抓取 暂时非必传)
                                //参数7:test_report(测试报告 非必传)
                                //参数8:svn_address (svn地址 必传)
                                //参数9:file_id(文件上传后返回的id  必填)




                                def param3 = "sys_id=${sys_id}&token=${token}&basic_name=${basic_name}&version=${version}&new_function_desc=${new_function_desc}&fix_bug_desc=${fix_bug_desc}&test_report=${test_report}&svn_address=${svn_address}&file_id=${file_id}"
                                println param3

                                def response3 = httpRequest consoleLogResponseBody: true,
                                        contentType: 'APPLICATION_FORM',
                                        httpMode: 'POST',
                                        requestBody: param3,
                                        url: "http://ip:port/AutoPublishController/software_info",
                                        validResponseCodes: '200'

                                println response3.status
                                println response3.content

                            } else {
                                println "上传文件失败"

                            }
                        } else {
                            println "获取token失败"
                        }

                    }else{
                        println "因为未生成制品,所以未上传产品发布系统!"
                    }

                }


            }
        }
    }

}