前提:第一次接触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”---选择语言
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 "因为未生成制品,所以未上传产品发布系统!"
}
}
}
}
}
}