前段时间无聊 又不想一直重复jenkins创建job的过程。就想写一个脚本,根据用户传入的参数或者json格式的数据创建jenkins job。目前只能靠开发填写一个json格式的文件,让后将文件给我,我去跑一下脚本才行。
由于本人python 基本不会 全是百度编程。所以比较挫。典型的人菜嫌烦花头精多。目前都是没有带if判断的。
Settings.json
{ "以下3项为必填项": "也可以使用默认值",
"是否为java项目,经过maven编译": "yes", "JavaSettings": { "pom文件路径": "pom.xml", "mvn编译命令": "clean install --DskipTests=true" }, "默认构建分支": "qa_car_loan", "代码git地址": "git@172.16.5.77:WDHC/web-service-all.git", "构建的job_name": "qa-wd-management-car-loan",
"以下2项为可选项": "也可以使用默认值",
"创建到指定view的name": "wangdao", "构建后shell(没有的话不做修改)": "echo 123" } |
创建通用的模板,我这边创建了2个。一个java 一个vue。文件夹里面内容如下
一个config.xml和builds文件夹。将/root/.jenkins/config.xml 复制一份为/root/.jenkins/exchange.xml。在/root/.jenkins/下创建insert.txt jobofview.txt format_insert.txt
其中java配置文件
<?xml version='1.0' encoding='UTF-8'?> <maven2-moduleset plugin="maven-plugin@3.0"> <actions/> <description></description> <keepDependencies>false</keepDependencies> <properties> <jenkins.model.BuildDiscarderProperty> <strategy class="hudson.tasks.LogRotator"> <daysToKeep>10</daysToKeep> <numToKeep>10</numToKeep> <artifactDaysToKeep>-1</artifactDaysToKeep> <artifactNumToKeep>-1</artifactNumToKeep> </strategy> </jenkins.model.BuildDiscarderProperty> <hudson.model.ParametersDefinitionProperty> <parameterDefinitions> <hudson.model.StringParameterDefinition> <name>branch</name> <description></description> <defaultValue>branch_qa</defaultValue> <trim>false</trim> </hudson.model.StringParameterDefinition> </parameterDefinitions> </hudson.model.ParametersDefinitionProperty> </properties> <scm class="hudson.plugins.git.GitSCM" plugin="git@3.9.1"> <configVersion>2</configVersion> <userRemoteConfigs> <hudson.plugins.git.UserRemoteConfig> <url>gitaddress</url> <credentialsId>17d7678b-e44d-4649-843f-4d0dc4f16fe9</credentialsId> </hudson.plugins.git.UserRemoteConfig> </userRemoteConfigs> <branches> <hudson.plugins.git.BranchSpec> <name>${branch}</name> </hudson.plugins.git.BranchSpec> </branches> <doGenerateSubmoduleConfigurations>false</doGenerateSubmoduleConfigurations> <submoduleCfg class="list"/> <extensions/> </scm> <canRoam>true</canRoam> <disabled>false</disabled> <blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding> <blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding> <triggers/> <concurrentBuild>false</concurrentBuild> <goals>clean install -DskipTests=true</goals> <aggregatorStyleBuild>true</aggregatorStyleBuild> <incrementalBuild>false</incrementalBuild> <ignoreUpstremChanges>true</ignoreUpstremChanges> <ignoreUnsuccessfulUpstreams>false</ignoreUnsuccessfulUpstreams> <archivingDisabled>false</archivingDisabled> <siteArchivingDisabled>false</siteArchivingDisabled> <fingerprintingDisabled>false</fingerprintingDisabled> <resolveDependencies>false</resolveDependencies> <processPlugins>false</processPlugins> <mavenValidationLevel>-1</mavenValidationLevel> <runHeadless>false</runHeadless> <disableTriggerDownstreamProjects>false</disableTriggerDownstreamProjects> <blockTriggerWhenBuilding>true</blockTriggerWhenBuilding> <settings class="jenkins.mvn.FilePathSettingsProvider"> <path>/root/.m2/settings_hengtian.xml</path> </settings> <globalSettings class="jenkins.mvn.FilePathGlobalSettingsProvider"> <path>/root/.m2/settings_hengtian.xml</path> </globalSettings> <reporters/> <publishers/> <buildWrappers/> <prebuilders/> <postbuilders> <hudson.tasks.Shell> <command>echo hello</command> </hudson.tasks.Shell> </postbuilders> <runPostStepsIfResult> <name>SUCCESS</name> <ordinal>0</ordinal> <color>BLUE</color> <completeBuild>true</completeBuild> </runPostStepsIfResult> </maven2-moduleset> |
vue
<?xml version='1.0' encoding='UTF-8'?> <project> <actions/> <description></description> <keepDependencies>false</keepDependencies> <properties> <jenkins.model.BuildDiscarderProperty> <strategy class="hudson.tasks.LogRotator"> <daysToKeep>10</daysToKeep> <numToKeep>10</numToKeep> <artifactDaysToKeep>-1</artifactDaysToKeep> <artifactNumToKeep>-1</artifactNumToKeep> </strategy> </jenkins.model.BuildDiscarderProperty> <hudson.model.ParametersDefinitionProperty> <parameterDefinitions> <hudson.model.StringParameterDefinition> <name>branch</name> <description></description> <defaultValue>branch_qa</defaultValue> <trim>false</trim> </hudson.model.StringParameterDefinition> </parameterDefinitions> </hudson.model.ParametersDefinitionProperty> </properties> <scm class="hudson.plugins.git.GitSCM" plugin="git@3.9.1"> <configVersion>2</configVersion> <userRemoteConfigs> <hudson.plugins.git.UserRemoteConfig> <url>gitaddress</url> <credentialsId>17d7678b-e44d-4649-843f-4d0dc4f16fe9</credentialsId> </hudson.plugins.git.UserRemoteConfig> </userRemoteConfigs> <branches> <hudson.plugins.git.BranchSpec> <name>${branch}</name> </hudson.plugins.git.BranchSpec> </branches> <doGenerateSubmoduleConfigurations>false</doGenerateSubmoduleConfigurations> <submoduleCfg class="list"/> <extensions/> </scm> <canRoam>true</canRoam> <disabled>false</disabled> <blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding> <blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding> <authToken>123456</authToken> <triggers/> <concurrentBuild>false</concurrentBuild> <builders> <hudson.tasks.Shell> <command>echo hello</command> </hudson.tasks.Shell> </builders> <publishers/> <buildWrappers/> </project> |
大致就是读取Settings.json文件里的信息,然后根据里面的信息,选择不同的模板文件,拷贝模板以新job的名称命名。替换新job文件config.xml里的内容,git地址这些。备份jenkins文件夹下的config.xml,然后查找jenkins的config.xml中所有的jobname的位置,获取config中jobname的位置,提取其中最靠后2个jobname的行信息,job_no1和job_no2,他们2者中间的行就是view下面所有job的名称。根据提供的行信息 提取jobname下面的jobname到jobofview.txt中,提取 jobofview.txt文件中<string></string>之间的jobname,加入新的job名称并排序,倒序排列该文件之后写入新的文件insert.txt。删exchange.xml中job_no1和job_no2行之间的内容.对排序好的insert.txt 加上<string></string>,成为format_insert.txt,在job_no1之后一行行倒序插入format_insert.txt的内容。再对exchange.xml文件格式化输出之后写入/root/.jenkins/config.xml,删除之前无用的文件(可选),重新加载jenkins配置。
中间多了很多插入,排序,添加的操作。主要是因为jenkins关于view视图的排序,job-name1应该排在job-name2之上,但是sort的时候job-name2会在job-name1上面 ,只能使用笨办法,一步一步将view信息修改好之后再重新插入。
#coding=utf-8 import json import shutil import os import pandas
#导入json 配置文件-------------------------------------- def loadFont(): f = open("/config_jenkins/Settings.json") global git_branch ,git_address ,git_address ,new_job_name ,view_name ,shell_command ,project_type , strofview_name, strofnew_job_name ,job_line ,exchange_file ,job_path ,job_path_configxml ,pom_adr ,mvn_command job_line='jobNames' exchange_file='/root/.jenkins/exchange.xml' setting = json.load(f) git_branch = setting[u'默认构建分支'] # //注意多重结构的读取语法 git_address= setting[u'代码git地址'] # //注意多重结构的读取语法 new_job_name = setting[u'构建的job_name'] # //注意多重结构的读取语法 view_name = setting[u'创建到指定view的name'] # //注意多重结构的读取语法 shell_command = setting[u'构建后shell(没有的话不做修改)'] # //注意多重结构的读取语法 project_type = setting[u'是否为java项目,经过maven编译'] project_type = project_type.lower() pom_adr = setting["JavaSettings"][u'pom文件路径'] mvn_command = setting["JavaSettings"][u'mvn编译命令'] strofview_name = "'"'<name>' + view_name + '</name>'"'" print strofview_name #strofnew_job_name = ' <string>new_job_name</string>\n' strofnew_job_name = "<string>" + new_job_name + "</string>\n" print strofnew_job_name job_path = '/root/.jenkins/jobs/' + new_job_name job_path_configxml = job_path + '/config.xml'
#拷贝自由风格的文件夹做为模板-------------------------------------- def copyfree_example_dir(): #coding=utf-8 example_dir='/config_jenkins/free-example' path=job_path print(path) path=path.strip() path=path.rstrip("\\") # 判断路径是否存在 isExists=os.path.exists(path) # 不存在 if not isExists: # 创建目录操作函数 print(path + u'已经创建') shutil.copytree(example_dir, path) return True #存在 else: print(path + u'目录存在') return False
shutil.copytree(example_dir, path)
#拷贝mvn的文件夹做为模板-------------------------------------- def copymvn_example_dir(): example_dir='/config_jenkins/mvn-example' #path='/tmp/test/test' path=job_path path=path.strip() path=path.rstrip("\\") # 判断路径是否存在 isExists=os.path.exists(path) # 不存在 if not isExists: # 创建目录操作函数 print(path+ u'已经创建') shutil.copytree(example_dir, path) return True #存在 else: print(path+ u'目录存在') return False
shutil.copytree(example_dir, path)
#修改free模板文件中的example.xml-------------------------------------- def change_xml_freeproject(): import xml.etree.ElementTree as ET tree = ET.parse(job_path_configxml) root = tree.getroot() for child in root: print(child.tag, child.attrib)
#替换defaultValue下默认分支 for name in root.iter('defaultValue'): new_name = str(git_branch) name.text = str(new_name) tree.write(job_path_configxml)
#替换git代码地址 for name in root.iter('url'): new_name = str(git_address) name.text = str(new_name) tree.write(job_path_configxml)
#替换构建后shell for name in root.iter('command'): new_name = str(shell_command) name.text = str(new_name) tree.write(job_path_configxml)
#修改mvn模板文件中的example.xml-------------------------------------- def change_xml_mvnproject(): import xml.etree.ElementTree as ET tree = ET.parse(job_path_configxml) root = tree.getroot() for child in root: print(child.tag, child.attrib)
#替换defaultValue下默认分支 for name in root.iter('defaultValue'): new_name = str(git_branch) name.text = str(new_name) tree.write(job_path_configxml)
#替换git代码地址 for name in root.iter('url'): new_name = str(git_address) name.text = str(new_name) tree.write(job_path_configxml)
#替换构建后shell for name in root.iter('command'): new_name = str(shell_command) name.text = str(new_name) tree.write(job_path_configxml)
#替换mvn命令 for name in root.iter('goals'): new_name = str(mvn_command) name.text = str(new_name) tree.write(job_path_configxml)
#替换pom文件原路径 #for name in root.iter(''): # new_name = str(pom_adr) # name.text = str(new_name) # tree.write(job_path_configxml)
#备份jenkins文件夹下的config.xml-------------------------------------- def copy(): import os,time oldFileName = '/root/.jenkins/config.xml'
oldFile = open(oldFileName,'rb') # 提取文件的后缀 fileFlagNum = oldFileName.rfind('.') if fileFlagNum > 0: # 截取文件名’.‘到最后 fileFlag = oldFileName[fileFlagNum:] # 组织新的文件名字 #newFileName = oldFileName[:fileFlagNum] + 时间 + fileFlag global newFileName newFileName = oldFileName[:fileFlagNum] + time.strftime('-%Y-%m-%d-%H:%M:%S') + fileFlag backupFileName =oldFileName[:fileFlagNum] + '-' + 'bak' +fileFlag # 创建新文件 newFile = open(newFileName, 'wb') backupFile = open(backupFileName, 'wb') # 把旧文件的内容复制到新文件中 for lineContent in oldFile.readlines(): newFile.write(lineContent) backupFile.write(lineContent) # 关闭文件 oldFile.close() newFile.close() backupFile.close()
#查找config中所有的jobname的位置-------------------------------------- def merge(): file = open(newFileName,"r") string='<name>'+view_name +'</name>' string=unicode.encode(string) print(123) print string #string='<name>test</name>' #print(type(string)) for num,value in enumerate(file): #if strofview_name2 in value: if string in value: print("the nume:%s,the value is %s") %(num,value) break else: pass #print(num) global i #num =num+1 i=num #print(type(num)) return merge file.close()
#获取viewname之后的2个jobname的位置信息-------------------------------------- def search_job(): else: file.close()
#根据job提供的line 提取jobname下面的jobname到jobofview.txt中-------------------------------------- def extract(): #strofnew_job_name=' <string>qa-wy-juwan-webaaa</string>\n' result=[] lnum = 0 with open(newFileName, 'r') as fd: for line in fd: lnum += 1; if (lnum >= job_no1+2) and (lnum <= job_no2): result.append(line) ab=line.strip() #print(line.strip()) print(ab) fd.close() print(result)
result.sort() result.append(strofnew_job_name) result.sort() f=open('/root/.jenkins/jobofview.txt','w') f.writelines(result) f.close()
def sort(): import pandas import re f=open('/root/.jenkins/jobofview.txt') result= [] iter_f=iter(f) #用迭代器循环访问文件中的每一行 for line in iter_f: regex = r'<string>(.*)</string>' del_string = re.findall(regex, line) if del_string: del_string = del_string[0] else: continue print(del_string) string = str(del_string) # import pdb;pdb.set_trace(); string = string + "\n" result.append(string) #print(type(result)) #print(result) f.close() #print(result)
result.sort(reverse=True) f=open('/root/.jenkins/insert.txt','w') # f.writelines('<string>') f.writelines(result) #f.writelines('</string>') f.writelines('\n') f.close()
#删除jobname之间的行-------------------------------------- def delete(): data = open(newFileName, 'rt').readlines() with open(newFileName, 'wt') as handle: handle.writelines(data[:job_no1+1]) handle.writelines(data[job_no2:])
#对排序好的insert.txt 加上<string> def TXTRead_Writeline(): #读取文件 import os my_file = '/root/.jenkins/format_insert.txt' if os.path.exists(my_file): #删除文件,可使用以下两种方法。 os.remove(my_file) #os.unlink(my_file) else: print 'no such file:%s'%my_file ms = open("/root/.jenkins/insert.txt") #逐行写入 for line in ms.readlines(): with open("/root/.jenkins/format_insert.txt","a") as mon: line = line.strip('\n') line = "<string>" + line + "</string>" +"\n" mon.write(line)
#with open("format_insert.txt", encoding="utf-8",mode="a") as data: # data.write("朝九晚五") file = open("/root/.jenkins/format_insert.txt", mode="a") #file.write("<comparator class=\"hudson.util.CaseInsensitiveComparator\"/>\n") file.close()
#在jobofview中插入新jobbane-------------------------------------- def insert_into_jobofview(): print(123123123123) print strofnew_job_name str1=strofnew_job_name+"\n" f = open('/root/.jenkins/jobofview.txt','a') f.write(str1) f.close()
#倒序排列文件-------------------------------------- def old_sort(): import pandas
f=open('/root/.jenkins/jobofview.txt') result= [] iter_f=iter(f) #用迭代器循环访问文件中的每一行 for line in iter_f: result.append(line) f.close() print(result)
result.sort(reverse=True) f=open('/root/.jenkins/insert.txt','w') f.writelines(result) f.writelines('\n') f.close()
#将jobname插入-------------------------------------- def insert_into_config(): #f1 = open(r'/root/.jenkins/insert.txt','rb') #f2= open(r'/root/.jenkins/config.xml','ab')
#i=0 #while True: # line = f1.readline() # i+=1 # if i>job_no1+1 and i<job_no2: # f2.write(line) # if i>200: # break
fp = file(newFileName) lines = [] for line in fp: lines.append(line.strip()) fp.close()
#
#fp2 = file('/root/.jenkins/insert.txt') fp2 = file('/root/.jenkins/format_insert.txt') lines2 = [] for line2 in fp2: lines.insert(job_no1+1, line2) s= '\n'.join(lines) fp2 = file(exchange_file, 'w') fp2.write(s) fp2.close()
#对xml文件格式化操作-------------------------------------- def prettyXml(element, indent, newline, level = 0): # elemnt为传进来的Elment类,参数indent用于缩进,newline用于换行 if element: #判断element是否有子元素 if element.text == None or element.text.isspace(): # 如果element的text没有内容 element.text = newline + indent * (level + 1) else: element.text = newline + indent * (level + 1) + element.text.strip() + newline + indent * (level + 1) #else: # 此处两行如果把注释去掉,Element的text也会另起一行 #element.text = newline + indent * (level + 1) + element.text.strip() + newline + indent * level temp = list(element) # 将elemnt转成list for subelement in temp: if temp.index(subelement) < (len(temp) - 1): # 如果不是list的最后一个元素,说明下一个行是同级别元素的起始,缩进应一致 subelement.tail = newline + indent * (level + 1) else: # 如果是list的最后一个元素, 说明下一行是母元素的结束,缩进应该少一个 subelement.tail = newline + indent * level prettyXml(subelement, indent, newline, level = level + 1) # 对子元素进行递归操作
#对格式化后的文件写入文件-------------------------------------- def doformat(): global root from xml.etree import ElementTree #导入ElementTree模块 tree = ElementTree.parse(exchange_file) #解析test.xml这个文件,该文件内容如上文 root = tree.getroot() #得到根元素,Element类 prettyXml(root, '\t', '\n') #执行美化方法 tree.write('/root/.jenkins/config.xml', encoding='UTF-8') ElementTree.dump(root) #显示出美化后的XML内容
#删除无用文件-------------------------------------- def delete_backfile(): import os if os.path.exists(newFileName): #删除文件,可使用以下两种方法。 print(newFileName) os.remove(newFileName) #os.unlink(my_file) else: print("no such file:" %s) %newFileName
#reload jenkins def reload_jenkins(): import requests url = 'http://172.16.129.72:8080/jenkins/reload'##定义http请求的地址,即1 headers = {'Accept': "application/xml",'Date':'Fri, 14 Apr 2017 02:07:17 GMT'}##定义header头,用dict方式定义,即3 #data = {'channel': 'vod.tv.cn', 'dataformat': 'json','date':'2017-04-13'}##定义参数,同样用dict定义,即4 #res = requests.post(url, data=data, headers=headers, auth=('tv2','l5f7jrRQttWdxsLmY7FV4+MA='))##post请求,且认证user=‘tv2’,password=‘sign’ #res = requests.post(url, headers=headers, auth=('admin','1u%VOMW$er'))##post请求,且认证user=‘tv2’,password=‘sign’ res = requests.post(url, headers=headers, auth=('admin','68d9a2ccdad1b1e60be581970c70487a'))##post请求,且认证user=‘tv2’,password=‘sign’ #res = requests.post(url, headers=headers, auth=('jiaminxu','119230775d4a15b4aaf5862c3f1d420a1a'))##post请求,且认证user=‘tv2’,password=‘sign’ #print res.text##就能看到打印结果了
#--------------------------------------以上为函数部分--------------------------------------
if __name__ == "__main__": loadFont()
if 'yes' in project_type:
print '构建JAVA项目' loadFont() copymvn_example_dir() change_xml_mvnproject() copy() merge() search_job() extract()
sort() #将jobview里的文件排序后插入insert.txt #insert_into_jobofview() TXTRead_Writeline() #对排序好的insert.txt 加上<string> delete() #删除jobname之间的行 insert_into_config() #在jobofview中插入新jobbane #prettyXml() #对xml文件格式化操作 doformat() #对格式化后的文件写入文件 reload_jenkins()
else:
print '构建自由项目' loadFont() copyfree_example_dir() change_xml_freeproject() copy() merge() search_job() extract()
sort() #将jobview里的文件排序后插入insert.txt #insert_into_jobofview() TXTRead_Writeline() #对排序好的insert.txt 加上<string> delete() #删除jobname之间的行 insert_into_config() #在jobofview中插入新jobbane #prettyXml() #对xml文件格式化操作 doformat() #对格式化后的文件写入文件 reload_jenkins() |
执行完毕后 不报错会出现以下界面
最后来个动图