文档章节

持续集成JenkinsAPI常见用法

彼得
 彼得
发布于 2014/02/08 17:24
字数 1809
阅读 31293
收藏 92

【背景】:部门在搞持续集成,使用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


© 著作权归作者所有

共有 人打赏支持
彼得

彼得

粉丝 39
博文 122
码字总数 38726
作品 0
深圳
程序员
私信 提问
加载中

评论(7)

扎克扎克
扎克扎克
非常号,最近正在做这方面工作。mark。
mopdzz
mopdzz
不明觉厉
彼得
彼得

引用来自“翟志军”的评论

可以看下这个:
https://github.com/zacker330/jenkins-ws-client

Java封装的api,不错,拿来参考下:)
彼得
彼得

引用来自“lavayan”的评论

Jenkins 提供的API应该满足大多数的需求,利用curl\wget获取xml数据固然可行,终究不如perl、python直接处理效率高

YES,最后一部分给出了用python处理的例子。
翟志军
翟志军
可以看下这个:
https://github.com/zacker330/jenkins-ws-client
anglix
anglix
Jenkins做得不错!
l
lavayan
Jenkins 提供的API应该满足大多数的需求,利用curl\wget获取xml数据固然可行,终究不如perl、python直接处理效率高
Jenkins API Token

Jenkins REST API提供了API token,使得可以在程序中使用API token进行认证(而不是使用你真实的密码)。 API token可以在用户个人设置界面查看 到用户→用户id→设置页面,在API Token区域点...

donhui
2015/09/08
1K
0
一步步搭建jenkins持续集成平台

【持续集成相关工具集】: CI-Server(Jenkins/Hudson.....) 代码管理工具(SVN/git...) java框架(maven) 覆盖率工具(c++:gcov java:maven cobertura插件) 静态扫描插件(jenkins插件) 覆...

彼得
2014/03/28
0
0
删除Jenkins JOB后清理workspace

如果Jenkins使用的Master-Slave多节点架构,删除Jenkins JOB后,相应JOB的slave节点的workspace不会被删除 stackoverflow上有相关的问答:http://stackoverflow.com/questions/20532705/del...

donhui
2016/05/19
3K
0
cat health(查看健康)

官网地址:cat health | Elasticsearch Reference [5.5] | Elastic cat health health从/_cluster/health获取到一个简洁的、单行表示同类信息。 GET /_cat/health?v 返回结果: epoch timest......

菜花_Q
03/29
0
0
JavaScript 全栈工程师培训教程

我现在的技术方向,前端是 React,后端是 Node,时间都投入在这两方面。 最近有一种感觉,我可以融汇贯通了,使用 JavaScript 全栈解决各种问题。 最初,我只是想整理一份技术清单,理清思路...

阮一峰
2016/11/15
0
0

没有更多内容

加载失败,请刷新页面

加载更多

(三)Honghu Cloud云架构一定时调度平台

2018-11-16 14:45:08 产品简介 鸿鹄云架构是一个完全由Java编写的开源任务调度框架,为企业在任务调度提供了简单却强大的机制。开发人员根据业务规则,使用调度平台简单配置,就可以让任务在...

itcloud
5分钟前
0
0
护航Lazada双11购物节 阿里云CDN全球化火力全开

摘要: Lazada是东南亚最大B2C平台,业务范围覆盖印度尼西亚、马来西亚、菲律宾、新加坡、泰国和越南六个东南亚国家,覆盖大约6亿消费者。在双11期间,阿里云CDN为Lazada电商内容加速,并且通...

阿里云官方博客
5分钟前
0
0
常用设计模式之代理模式解析

1. 简介 代理模式(Proxy Pattern)是常用设计模式之一。代理模式的定义:Provide a surrogate or placeholder for another object to controlaccess to it(为其他对象提供一种代理以控制对这个...

老道士
5分钟前
0
0
Vue瀑布流插件的使用示例

我自己写的一个的Vue瀑布流插件,列数自适应,不用设置每个卡片的高度。 测试页面:Page.vue 模板页面:WaterFollow.vue 和 WFColumn.vue 在Page.vue中,修改itemW的值,设置每列的最小宽度。...

peakedness丶
6分钟前
0
0
多种负载均衡算法及其Java代码实现【网络上较好的转载】

首先给大家介绍下什么是负载均衡(来自百科) 负载均衡 建立在现有网络结构之上,它提供了一种廉价有效透明的方法扩展 网络设备和 服务器的带宽、增加 吞吐量、加强网络数据处理能力、提高网...

stys352
10分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部