脚本的功能是查看当前所有task,如果发现同一个url触发的task,就会abort之前的task,只保留最新的。
流程:
- 在job_list填写需要kill的job路径,如果是多层,可以只写入顶层,脚本会递归查询,如填写devops,他会
把子目录查询出来 - 通过jenkins的api查询build的来源,是同一个来源。保存最新的时间。当后面的job时间比他早,干掉后面的job
添加crontab定时任务:*/5 * * * * python3 stop_build.py
import json
import os
import re
import time
import logging
import jenkins
import requests
from lxml import etree
from configparser import ConfigParser
logger = logging.getLogger()
logging.basicConfig(
format='%(levelname)s:%(asctime)s : %(lineno)d :%(message)s',
datefmt='%Y/%m/%d %H:%M:%S',
filename='earth_job_kill.log',
level=logging.WARNING)
class JenkinsStopTask(object):
def __init__(self, user, passwd, job_list=[]):
self.host = "https://ci-earth.hobot.cc:8443"
self.user = user
self.password = passwd
self.server = None
self.init_server()
self.job_list = job_list
def init_server(self):
self.server = jenkins.Jenkins(self.host,
username=self.user,
password=self.password)
def get_running_build(self, job):
tmp_url = ''
if isinstance(job, str):
job = job.split('/')
flag = False
for jj in job:
if jj == 'view':
tmp_url += f'/{jj}'
flag = True
elif flag:
tmp_url += f'/{jj}'
flag = False
else:
tmp_url += f'/job/{jj}'
url = f'{self.host}{tmp_url}'
api_url = f'{self.host}{tmp_url}/api/json'
response = self.server.jenkins_open(requests.Request('GET', api_url))
response_json = json.loads(response)
if response_json['_class'] == 'org.jenkinsci.plugins.workflow.job.WorkflowJob':
response = self.server.jenkins_open(requests.Request('GET', url))
element = etree.HTML(response)
self.parse_job(element, response_json['fullName'])
else:
# If the job is not a WorkflowJob, it may contain nested jobs
for sub_job in response_json['jobs']:
if sub_job['_class'] == 'org.jenkinsci.plugins.workflow.job.WorkflowJob':
sub_job_response = self.server.jenkins_open(requests.Request('GET', sub_job['15dd']))
sub_job_element = etree.HTML(sub_job_response)
sub_full_name = response_json['fullName'] + '/' + sub_job['name'] # Use 'name' instead of splitting URL
#print(sub_full_name)
self.parse_job(sub_job_element, sub_full_name)
# Recursively call get_running_build for nested jobs
#self.get_running_build(sub_full_name) # Pass sub job name for recursion
else:
sub_full_name = response_json['fullName'] + '/' + sub_job['name'] # Use 'name' instead of splitting URL
self.get_running_build(sub_full_name)
def parse_job(self, element, job):
task_list = element.xpath('//*[@id="buildHistory"]/div[2]/table/tr/td')
running_map = dict()
for task in task_list:
res = task.xpath('div[1]/div/a/span/svg/@tooltip')
if res and 'In progress' in res[0]:
try:
task_name = None
start_time = None
# merge requests
if task.xpath('div[4]/a/text()'):
merge_text = task.xpath('div[4]/a/text()')[0]
if merge_text and 'GitLab Merge Request' in merge_text:
task_name_array = task.xpath('./div[4]/a/@href')
if task_name_array:
task_name = task_name_array[0]
# ph 重复任务
if task.xpath('div[3]/div[1]/a/span/text()'):
ph_text = task.xpath('div[3]/div[1]/a/span/text()')[0]
task_name_array = re.search(r'D(\d+)',
ph_text)
if task_name_array:
task_name = task_name_array.group(1)
# 不是这两项,不处理
if not task_name:
continue
index = None
start_time_array = task.xpath('./div[2]/@time')
if start_time_array:
start_time = start_time_array[0]
index_array = task.xpath('./div[1]/a/text()')
if index_array:
index_str = index_array[0]
index = re.search(r'(\d+)', index_str).group(1)
if (task_name and start_time and index) is None:
continue
if running_map.get(task_name,
None) is None:
running_map[task_name] = {
'start_time': start_time,
'index': index
}
elif running_map[task_name]['start_time'] > start_time:
self.stop_task(job, index)
else:
last_task = running_map[task_name]
running_map[task_name] = {
'start_time': start_time,
'index': index
}
self.stop_task(job, last_task[index])
except Exception as err:
logger.error(err)
#logging.warning(str(running_map))
def stop_task(self, job, index):
if isinstance(job, list):
job = '/'.join(job)
print(f"{job} --- {index}")
logging.warning(f"{job} --- {index}")
self.server.stop_build(job, index)
def handle(self):
# for _ in range(2):
for job in self.job_list:
self.get_running_build(job)
#time.sleep(20)
if __name__ == '__main__':
cp = ConfigParser()
config_path = os.path.dirname(os.path.abspath(__file__))
cfg = os.path.join(config_path, 'config.cfg')
cp.read(cfg)
username = cp.get('jenkins', 'username')
password = cp.get('jenkins', 'password')
job_list = [
#'test/test',
]
jen = JenkinsStopTask(username, password, job_list)
jen.handle()
config.cfg格式
[jenkins]
username =
password =