摘要: jenkins(持续集成开源工具)提供了丰富的api接口,基本上所有的操作都可以使用curl来从后台调度,包括:创建项目,禁用项目,启用项目,获取项目描述,获取配置文件,普通触发,scm触发,带参数触发,带补丁触发。同时也可以使用python 库 jenkinsapi https://pypi.python.org/pypi/jenkinsapi

【背景】:部门在搞持续集成,使用jenkins作为核心调度,要再其基础上进行二次封装,所以需要研究下jenkins的api。笔者主要负责搭建平台,在研究用法也花费了些时间,本文主要做个简要的记录,希望能为各位朋友节省时间。

【环境】:(默认读者已经具备了基本的持续集成经验和jenkins用法)

1.Jenkins1.455

2. 系统Suse

3. Tomcat 6.0.37

4. Java 1.6.0_26

5. patch-parameter

【API介绍】

Jenkins提供了html、json、python API,实质都是以http get/post方式调用的。查看http://www.xxx.xxx/jenkins/api/ 即可得到相应的说明,如图:

【API实践】

1.创建

curl -X POST http://www.xxx.xxx/jenkins/createItem?name=JavaStd  --user peterguo:peterguo --data-binary "@javastd.config.xml" -H "Content-Type: text/xml"

2.禁用

curl -X POST http://www.xxx.xxx/jenkins/job/JavaStd/disable  --user peterguo:peterguo

3.启用

curl -X POST http://www.xxx.xxx/jenkins/job/JavaStd/enable --user peterguo:peterguo

4.删除

curl -X POST http://www.xxx.xxx/jenkins/job/JavaStd/doDelete --user peterguo:peterguo

5.获取项目描述

curl -X GET http://www.xxx.xxx/jenkins/job/JavaStd/description --user peterguo:peterguo

6.获取配置文件

curl -X GET http://www.xxx.xxx/jenkins/job/JavaStd/config.xml --user peterguo:peterguo

7.触发SCM检查

curl -X GET http://www.xxx.xxx/jenkins/job/JavaStd/polling --user peterguo:peterguo

8.普通触发

curl -X GET http://www.xxx.xxx/jenkins/job/JavaStd/build --user peterguo:peterguo

9.带参数触发

curl -X GET "http://www.xxx.xxx/jenkins/job/helloworld-freestyle/buildWithParameters?bAllTest=&Choices=2&strParam=abc" --user peterguo:peterguo

10.带文件触发

curl  -X POST "http://localhost:8080/job/Demo/buildWithParameters?assertMethod=online" -F "input=@atest.txt"

11.参数和补丁触发

curl -X POST "http://www.xxx.xxx/jenkins/job/helloworld-freestyle/buildWithParameters?bAllTest=&Choices=2&strParam=abc" --user peterguo:peterguo -F "action=upload" -F "patch.diff=@OtherTest.java.patch"

注:带补丁触发需要先安装补丁插件,并设置项目的补丁参数

【通过Python-curl库调用】

提供python使用pycurl调用的例子片段,实际和curl调用一样,优点是易整合。

import pycurl
url = "http://10.129.145.112:8081/jenkins/job/helloworld-freestyle/config.xml"
crl = pycurl.Curl()
crl.setopt(pycurl.VERBOSE,1)
crl.setopt(pycurl.FOLLOWLOCATION, 1)
crl.setopt(pycurl.MAXREDIRS, 5)
crl.setopt(pycurl.USERPWD, "peterguo:peterguo") crl.setopt(pycurl.CONNECTTIMEOUT, 60)
crl.setopt(pycurl.TIMEOUT, 300)
crl.setopt(pycurl.HTTPPROXYTUNNEL,1)
crl.fp = StringIO.StringIO() crl.setopt(pycurl.URL, url)
crl.setopt(crl.WRITEFUNCTION, crl.fp.write)
crl.perform()
ret = crl.fp.getvalue()
 

【通过Python-jenkinsapi库调用】

这里给出代码

from jenkinsapi.jenkins import Jenkins

class CJenkinsAPI():
'''
均采用同步设置超时机制
创建项目:输入:configid planid
创建任务:输入:configid planid 返回:返回码 msg buildid 额外动作:不写SQL
查询任务:输入:configid planid taskid 返回:返回码 msg buildid 额外动作:结束更新SQL(包括成功或失败),未结束则不处理
终止任务:输入:configid planid taskid 返回:返回码 msg buildid 额外动作:终止成功写SQL '''
__doc__ = '''Usage: \t\tCJenkinsAPI.createProject\t\tCJenkinsAPI.triggerBuild\t\t''' _strConfigTemplatePath = ""
_strConfigDataPath = "" def __init__(self):
import pycurl
pass def __del__(self):
pass @staticmethod
def createProject(nPlanId, strConfigId):
'''
Return:返回码/返回信息
先根据配置文件生成项目
'''
#用于测试
nPlanId = 14
strConfigId = "D1057406" #返回
nRet, strMsg, nBuild = 0, "", 0 #配置文件模版
strConfigTemplate = CJenkinsAPI._strConfigTemplatePath + "/config.template.xml" #用planID和配置ID作为项目名
strProjectName = "P%d-%s" % (nPlanId, strConfigId ) #访问数据库拿到构建节点IP和SVN
strBuildNodeIP = ""
strProjectSVN = "" oProxy = CSqlProxy("10.129.145.112", "ci_test", "ci_test", "ci_plat")
#SVN从t_build_plan中取
lSelectRet = CSqlProxy.selectFromTable(oProxy.m_oCon, "t_build_plan", ["f_svn"], " where f_plan_id='%d' " % nPlanId)
strProjectSVN = lSelectRet[0]["f_svn"]
#配置信息从t_ci_config中取
lSelectRet = CSqlProxy.selectFromTable(oProxy.m_oCon, "t_ci_config", ["f_node_ip", "f_run_param"], " where f_config_id='%s' " % strConfigId)
strBuildNodeIP = lSelectRet[0]["f_node_ip"]
strRunParam = lSelectRet[0]["f_run_param"]
oProxy.close() strNodeFlag = {True:"", False:"slave_"}["10.129.145.112" in strBuildNodeIP]
dReplaceInfo = {"PROJ_DESC" : "This is generate by Ci-plat, with plan_id[%d] and config_id[%s]" % (nPlanId, strConfigId),\
"SVN_URL" : strProjectSVN.replace("http://tc-svn.tencent.com", "svn://172.27.198.49:8081"),\
"BUILD_NODE_IP" : strNodeFlag + strBuildNodeIP,\
"BUILD_SCRIPT" : '''sh build.sh %s ''' % strRunParam, \
"JUNIT_TEST_PATH" :"target/surefire-reports/*.xml", \
"COVERAGE_PATH" :"target/site/cobertura/", \
} #利用模版生成配置文件
oConf = CCiConfig(strConfigTemplate, dReplaceInfo)
strCurConfigXml = CJenkinsAPI._strConfigDataPath + "/" + strProjectName + ".config.xml"
oConf.dump2file(strCurConfigXml) strCommand = 'curl -X POST http://10.129.145.112:8081/jenkins/createItem?name=%s --user peterguo:peterguo --data-binary "@%s" -H "Content-Type: text/xml"' % (strProjectName, strCurConfigXml)
nRet = os.system(strCommand)
strMsg = {True:"SucceedCreate,Url:", False:"FailedCreate,Url:"}[nRet==0]
print "%d|%s|%d" % (nRet, tran2UTF8(strMsg)+"[http://10.129.145.112:8081/jenkins/job/%s]" % strProjectName, nBuild) @staticmethod
def triggerBuild(nPlanId, strConfigId):
'''
Return:
触发前先更新配置文件,使用远程脚本
触发前获取要出发的编号
'''
#返回
nRet, strMsg, nBuild = 0, "", 0 #配置文件模版
strConfigTemplate = CJenkinsAPI._strConfigTemplatePath + "/config.template.xml" #用planID和配置ID作为项目名
strProjectName = "P%d-%s" % (nPlanId, strConfigId ) #访问数据库拿到构建节点IP和SVN
strBuildNodeIP = ""
strProjectSVN = "" oProxy = CSqlProxy("10.129.145.112", "ci_test", "ci_test", "ci_plat")
#SVN从t_build_plan中取
lSelectRet = CSqlProxy.selectFromTable(oProxy.m_oCon, "t_build_plan", ["f_svn"], " where f_plan_id='%d' " % nPlanId)
strProjectSVN = lSelectRet[0]["f_svn"]
#配置信息从t_ci_config中取
lSelectRet = CSqlProxy.selectFromTable(oProxy.m_oCon, "t_ci_config", ["f_node_ip", "f_run_param"], " where f_config_id='%s' " % strConfigId)
strBuildNodeIP = lSelectRet[0]["f_node_ip"]
strRunParam = lSelectRet[0]["f_run_param"]
oProxy.close() strNodeFlag = {True:"", False:"slave_"}["10.129.145.112" in strBuildNodeIP]
dReplaceInfo = {"PROJ_DESC" : "This is generate by Ci-plat, with plan_id[%d] and config_id[%s]" % (nPlanId, strConfigId),\
"SVN_URL" : strProjectSVN.replace("http://tc-svn.tencent.com", "svn://172.27.198.49:8081"),\
"BUILD_NODE_IP" : strNodeFlag + strBuildNodeIP,\
"BUILD_SCRIPT" : '''sh build.sh %s ''' % strRunParam, \
"JUNIT_TEST_PATH" :"target/surefire-reports/*.xml", \
"COVERAGE_PATH" :"target/site/cobertura/", \
} #利用模版生成配置文件
oConf = CCiConfig(strConfigTemplate, dReplaceInfo)
strCurConfigXml = CJenkinsAPI._strConfigDataPath + "/" + strProjectName + ".config.xml"
oConf.dump2file(strCurConfigXml) #更新配置文件
strCommand = 'curl -X POST http://10.129.145.112:8081/jenkins/job/%s/config.xml --user peterguo:peterguo --data-binary "@%s" -H "Content-Type: text/xml"' % (strProjectName, strCurConfigXml)
nRet = os.system(strCommand)
strMsg += {True:"更新配置成功", False:"更新配置失败"}[nRet==0] #获取下一次构建编号
nBuild = Jenkins("http://10.129.145.112:8081/jenkins","peterguo","peterguo")[strProjectName.encode("utf8")].get_next_build_number() #触发构建
strCommand = 'curl -X POST http://10.129.145.112:8081/jenkins/job/%s/build --user peterguo:peterguo ' % (strProjectName)
nRet = os.system(strCommand)
strMsg = {True:"SucceedTrigger,Url:", False:"FailedTrigger,Url:"}[nRet==0]
print "%d|%s|%d" % (nRet, tran2UTF8(strMsg)+"[http://10.129.145.112:8081/jenkins/job/%s/%d]" % (strProjectName, nBuild), nBuild ) @staticmethod
def infoBuild(nPlanId, strConfigId, nTaskId):
'''
Return:
'''
strProjectName = "P%d-%s" % (nPlanId, strConfigId )
oProxy = CSqlProxy("10.129.145.112", "ci_test", "ci_test", "ci_plat")
strWhere = " where f_task_id='%d' " % int(nTaskId)
lSelectRet = CSqlProxy.selectFromTable(oProxy.m_oCon, "t_build_task", ["f_build_id"], strWhere)
oProxy.close()
nBuildId = int(lSelectRet[0]["f_build_id"]) oCurBuild = Jenkins("http://10.129.145.112:8081/jenkins","peterguo","peterguo")[strProjectName.encode("utf8")].get_build(nBuildId)
bRunning = oCurBuild.is_running()
if bRunning == True:
print "1|Running|%d" % nBuildId
return #最重要更新的数据
dResult2Sql = {} #取测试用例结果的个数信息
if oCurBuild.has_resultset():
dResult = oCurBuild.get_actions()
else:
dResult = {"failCount":0, "totalCount":0, "skipCount":0} oDeltaDur = oCurBuild.get_duration()
oBuildBegin = utc2LocalDatetime(oCurBuild.get_timestamp())
oBuildEnd = oBuildBegin + oDeltaDur
dResult2Sql["f_case_fail"] = dResult['failCount']
dResult2Sql["f_case_total"] = dResult['totalCount']
dResult2Sql["f_case_skip"] = dResult['skipCount']
dResult2Sql["f_build_duration"] = "%.3f" % (oDeltaDur.days * 24 * 60 + oDeltaDur.seconds / 60.0)
dResult2Sql["f_build_url"] = oCurBuild.baseurl
dResult2Sql["f_build_result"] = {True:0, False:1}[oCurBuild.is_good()]
dResult2Sql["f_task_status"] = TASK_DONE
dResult2Sql["f_build_time"] = oBuildBegin.strftime("%Y-%m-%d %H:%M:%S")
dResult2Sql["f_build_end"] = oBuildEnd.strftime("%Y-%m-%d %H:%M:%S")
dResult2Sql["f_msg_info"] = tran2GBK("任务完成,收集数据完成") #任务已经完成,需要入库相关数据,更新相关状态
oProxy = CSqlProxy("10.129.145.112", "ci_test", "ci_test", "ci_plat")
strWhere = " where f_task_id='%d' " % int(nTaskId)
CSqlProxy.updateValueToDBTable(oProxy.m_oCon, "t_build_task", dResult2Sql.keys(), dResult2Sql.values(), strWhere)
oProxy.close()
#for item in dResult2Sql.items():
# print item[0], str(item[1])
print "%d|%s|%d" % (0, "SucceedUpdated", nBuildId) @staticmethod
def stopBuild(nPlanId, strConfigId, nTaskId):
'''
Return:
'''
strProjectName = "P%d-%s" % (nPlanId, strConfigId )
oProxy = CSqlProxy("10.129.145.112", "ci_test", "ci_test", "ci_plat")
strWhere = " where f_task_id='%d' " % int(nTaskId)
lSelectRet = CSqlProxy.selectFromTable(oProxy.m_oCon, "t_build_task", ["f_build_id"], strWhere)
oProxy.close()
nBuildId = int(lSelectRet[0]["f_build_id"]) oCurBuild = Jenkins("http://10.129.145.112:8081/jenkins","peterguo","peterguo")[strProjectName.encode("utf8")].get_build(nBuildId)
bRunning = oCurBuild.is_running()
if bRunning == False:
print "2|AlreadyStopped|%d" % nBuildId
return #触发停止命令
oCurBuild.stop() #等停止
oCurBuild.block_until_complete() #最重要更新的数据
dResult2Sql = {} #取测试用例结果的个数信息
if oCurBuild.has_resultset():
dResult = oCurBuild.get_actions()
else:
dResult = {"failCount":0, "totalCount":0, "skipCount":0} oDeltaDur = oCurBuild.get_duration()
oBuildBegin = utc2LocalDatetime(oCurBuild.get_timestamp())
oBuildEnd = oBuildBegin + oDeltaDur
dResult2Sql["f_case_fail"] = dResult['failCount']
dResult2Sql["f_case_total"] = dResult['totalCount']
dResult2Sql["f_case_skip"] = dResult['skipCount']
dResult2Sql["f_build_duration"] = "%.3f" % (oDeltaDur.days * 24 * 60 + oDeltaDur.seconds / 60.0)
dResult2Sql["f_build_url"] = oCurBuild.baseurl
dResult2Sql["f_build_result"] = {True:0, False:1}[oCurBuild.is_good()]
dResult2Sql["f_task_status"] = TASK_ABORTED
dResult2Sql["f_build_time"] = oBuildBegin.strftime("%Y-%m-%d %H:%M:%S")
dResult2Sql["f_build_end"] = oBuildEnd.strftime("%Y-%m-%d %H:%M:%S")
dResult2Sql["f_msg_info"] = tran2GBK("TaskStopped") #任务已经完成,需要入库相关数据,更新相关状态
oProxy = CSqlProxy("10.129.145.112", "ci_test", "ci_test", "ci_plat")
strWhere = " where f_task_id='%d' " % int(nTaskId)
CSqlProxy.updateValueToDBTable(oProxy.m_oCon, "t_build_task", dResult2Sql.keys(), dResult2Sql.values(), strWhere)
oProxy.close()
#for item in dResult2Sql.items():
# print item[0], str(item[1]) print "%d|%s|%d" % (1, tran2UTF8("SucceedStopped"), nBuildId) @staticmethod
def deleteProject(nPlanId, strConfigId):
'''
Return:返回码/返回信息 curl -X POST http://10.129.145.112:8081/jenkins/job/JavaStd/doDelete --user peterguo:peterguo
'''
strProjectName = "P%d-%s" % (nPlanId, strConfigId )
strCommand = 'curl -X POST http://10.129.145.112:8081/jenkins/job/%s/doDelete --user peterguo:peterguo' % (strProjectName)
CColorPrint.colorPrintStr("CMD:[%s]" % strCommand, "green") nRet = os.system(strCommand)
strMsg = {True:"SucceedDeleted", False:"FailedDeleted"}[nRet==0]
print nRet, tran2UTF8(strMsg), 0

jenkins使用记录转自https://my.oschina.net/sanpeterguo/blog/197931的更多相关文章

  1. selenium定位元素(本内容从https://my.oschina.net/flashsword/blog/147334处转载)

    注明:本内容从https://my.oschina.net/flashsword/blog/147334处转载. 在使用selenium webdriver进行元素定位时,通常使用findElemen ...

  2. https://my.oschina.net/huangyong/blog/161419

    https://my.oschina.net/huangyong/blog/161419

  3. https://my.oschina.net/reesechou/blog/492265

    https://my.oschina.net/reesechou/blog/492265

  4. Echarts 的 Java 封装类库 转自 https://my.oschina.net/flags/blog/316920

    转自: https://my.oschina.net/flags/blog/316920 Echarts 的 Java 封装类库:http://www.oschina.net/p/echarts-ja ...

  5. linux svn 中文 https://my.oschina.net/VASKS/blog/659236

    https://my.oschina.net/VASKS/blog/659236 设置服务器: export LC_ALL=zh_CN.UTF-8长久之计, echo export LC_ALL=zh ...

  6. python和scrapy的安装【转:https://my.oschina.net/xtfjt1988/blog/364577】

    抓取网站的代码实现很多,如果考虑到抓取下载大量内容scrapy框架无疑是一个很好的工具.Scrapy = Search+Pyton.下面简单列出安装过程.PS:一定要按照Python的版本下载,要不然 ...

  7. c3p0的几种使用方式(原文地址: https://my.oschina.net/liangtee/blog/101047)

    package com.c3p0.test; import java.sql.Connection; import java.sql.SQLException; import java.beans.P ...

  8. python学习笔记之读取配置文件【转自https://my.oschina.net/u/3041656/blog/793467】

    [转自https://my.oschina.net/u/3041656/blog/793467] 最近在接触利用python来写测试框架,本人也是个刚接触python,所以是个小菜鸟,今天开始,一点点 ...

  9. https://www.oschina.net/project/lang/19/java

    https://www.oschina.net/project/lang/19/java

随机推荐

  1. 【SaltStack官方版】—— states教程, part 2 - 更复杂的states和必要的事物

    states tutorial, part 2 - more complex states, requisites 本教程建立在第1部分涵盖的主题上.建议您从此处开始. 在Salt States教程的 ...

  2. NOIP模拟赛(by hzwer) T1 小奇挖矿

    [题目背景] 小奇要开采一些矿物,它驾驶着一台带有钻头(初始能力值 w)的飞船,按既定 路线依次飞过喵星系的 n 个星球. [问题描述] 星球分为 2 类:资源型和维修型. 1. 资源型:含矿物质量 ...

  3. LeetCode--142--环形链表II(python)

    给定一个链表,返回链表开始入环的第一个节点. 如果链表无环,则返回 null. 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始). 如果 pos 是 - ...

  4. php array_pop()函数 语法

    php array_pop()函数 语法 作用:删除数组中的最后一个元素.博智达 语法:array_pop(array) 参数: 参数 描述 array 必需.规定数组.     说明:返回数组的最后 ...

  5. Django REST framework入门 (转自中文文档)

    快速入门 我们将创建一个简单的允许管理员用户查看和编辑系统中的用户和组的API. 项目设置 创建一个名为 tutorial 的新django项目,然后启动一个名为 quickstart 的新app. ...

  6. equals深入理解

    package cn.galc.test; public class TestEquals { public static void main(String[] args) { /** * 这里使用构 ...

  7. MSSQL 如何导出db所有用户权限创建语句

    use dbgoDECLARE @Database varchar(255),@loginName varchar(255),@roleName varchar(255),@sql nvarchar( ...

  8. element-ui的rules全局验证

    原文:https://www.jianshu.com/p/6a29e9e51b61 rules.js var QQV = (rule, value, callback) => { debugge ...

  9. 并发测试JMeter及发送Json请求

    1.下载 提前安装好jdk1.8 官网下载地址:http://jmeter.apache.org/download_jmeter.cgi 2.解压,双击bin/jmeter.bat 3.jmeter配 ...

  10. drop_duplicates()函数

    1dataframe删除某一列的重复元素,默认只留下第一次出现的 inplace参数设置为true时直接在原数据上修改,为False时,生成副本. 注意所有函数中inplace一旦设置为True,此时 ...