jenkins - 詹金斯计划的备份管道 - 确保所有作业在运行前停止
问题描述
我有一个通宵运行的 Jenkins 管道来进行备份。我需要找到一种方法,仅在所有其他作业完成后才运行管道,并确保同时不会触发其他作业。这应该类似于这个插件https://plugins.jenkins.io/exclusive-execution/正在做的事情。但是声明性管道不支持“独占执行”。
我附上我的 Jenkinsfile 以防万一有人需要看一下:
def BACKUP_DATETIME = new Date().format('yyyy_MM_dd_HH_mm_ss', TimeZone.getTimeZone('Canada/Eastern'))
pipeline {
agent { label 'master' }
options {
//Build options
disableResume()
disableConcurrentBuilds()
buildDiscarder(
logRotator (
artifactDaysToKeepStr: '10',
artifactNumToKeepStr: '1',
daysToKeepStr: '30',
numToKeepStr: '30'
)
)
}
triggers { cron('TZ=Canada/Eastern\n0 3 * * *') }
environment {
GIT_SSH_KEY_ID = 'gitlab_builduser'
BACKUP_PREFIX_NAME = 'jenkins-back-'
BACKUP_REPO_NAME = "jenkins_backups"
BACKUP_REPO_URL = "git@XXX:XX/${env.BACKUP_REPO_NAME}.git"
NUMBER_OF_BACKUPS = '7'
GOOGLE_CHAT_TOKEN = 'XXXXXF'
JENKINS_VERSION = ''
}
stages {
stage('Init') {
steps {
script {
env.JENKINS_VERSION = sh(script: "java -jar /usr/share/jenkins/jenkins.war --version", returnStdout: true).trim()
}
dir("/tmp") {
withCredentials([sshUserPrivateKey(credentialsId: "${env.GIT_SSH_KEY_ID}", keyFileVariable: 'SSH_KEY', usernameVariable: 'SSH_USER')]) {
withEnv(["GIT_SSH_COMMAND=ssh -i ${SSH_KEY}"]) {
sh '''
if [ ! -d ${BACKUP_REPO_NAME} ]
then
git clone ${BACKUP_REPO_URL}
else
cd ${BACKUP_REPO_NAME}
git fetch origin
git reset --hard origin/master
fi
'''
}
}
}
}
}
stage('Backup') {
steps {
dir ('jenkins_backup') {
sh """
chmod +x ./jenkins-backup.sh
./jenkins-backup.sh ${JENKINS_HOME} /tmp/${env.BACKUP_REPO_NAME}/${BACKUP_PREFIX_NAME}_${BACKUP_DATETIME}.tar.gz
"""
}
}
}
stage('Upload') {
steps {
// TO_DO: SAVE THE BACKUP file
dir("/tmp/${env.BACKUP_REPO_NAME}") {
withCredentials([sshUserPrivateKey(credentialsId: "${env.GIT_SSH_KEY_ID}", keyFileVariable: 'SSH_KEY', usernameVariable: 'SSH_USER')]) {
withEnv(["GIT_SSH_COMMAND=ssh -i ${SSH_KEY}"]) {
sh '''
git config user.email "${SSH_USER}@email.com"
git config user.name "${SSH_USER}"
# backup only keep the lastest X backup-files
ls -tp ${BACKUP_PREFIX_NAME}_*.tar.gz | grep -v '/$' | tail -n +$(expr ${NUMBER_OF_BACKUPS} + 1) | xargs -I {} rm -- {}
# Push to git
git add --all
git status
git commit --amend -CHEAD --allow-empty
git push --force-with-lease origin master
env
'''
}
}
}
}
}
}
post {
failure {
hangoutsNotify message: "${JOB_BASE_NAME} faild!",token: "${env.GOOGLE_CHAT_TOKEN}",threadByJob: true
}
}
}
解决方案
我最终编写了一个 groovy 脚本来满足我的需要。该脚本将列出除备份作业之外的所有当前正在运行和排队的作业,如果其中一个列表不为空,则放置一个计时器。当所有作业都处于空闲状态时,备份将继续运行。
我将在此处附上我的脚本:
詹金斯文件:
def BACKUP_DATETIME = new Date().format('yyyy_MM_dd_HH_mm_ss', TimeZone.getTimeZone('Canada/Eastern'))
pipeline {
agent { label 'master' }
options {
//Build options
disableResume()
disableConcurrentBuilds()
buildDiscarder(
logRotator (
artifactDaysToKeepStr: '10',
artifactNumToKeepStr: '1',
daysToKeepStr: '30',
numToKeepStr: '30'
)
)
}
triggers { cron('TZ=Canada/Eastern\n0 3 * * *') }
environment {
GIT_SSH_KEY_ID = 'gitlab_builduser'
BACKUP_PREFIX_NAME = 'jenkins-backup'
BACKUP_REPO_NAME = "jenkins_backups"
BACKUP_REPO_URL = "git@XXXX/${env.BACKUP_REPO_NAME}.git"
NUMBER_OF_BACKUPS = '7'
GOOGLE_CHAT_TOKEN = 'XXXX'
JENKINS_VERSION = ''
}
stages {
stage('Init') {
steps {
script {
env.JENKINS_VERSION = sh(script: "java -jar /usr/share/jenkins/jenkins.war --version", returnStdout: true).trim()
def safeBackupModule = load("${WORKSPACE}/jenkins_backup/safe_backup_run.groovy")
safeBackupModule.jenkins_safe_backup("${env.JOB_NAME}")
}
dir("/tmp") {
withCredentials([sshUserPrivateKey(credentialsId: "${env.GIT_SSH_KEY_ID}", keyFileVariable: 'SSH_KEY', usernameVariable: 'SSH_USER')]) {
withEnv(["GIT_SSH_COMMAND=ssh -i ${SSH_KEY}"]) {
sh '''
if [ ! -d ${BACKUP_REPO_NAME} ]
then
git clone ${BACKUP_REPO_URL}
else
cd ${BACKUP_REPO_NAME}
git fetch origin
git reset --hard origin/master
fi
'''
}
}
}
}
}
stage('Backup') {
steps {
dir ('jenkins_backup') {
sh """
chmod +x ./jenkins-backup.sh
./jenkins-backup.sh ${JENKINS_HOME} /tmp/${env.BACKUP_REPO_NAME}/${BACKUP_PREFIX_NAME}_${BACKUP_DATETIME}.tar.gz
"""
}
}
}
stage('Upload') {
steps {
// TO_DO: SAVE THE BACKUP file
dir("/tmp/${env.BACKUP_REPO_NAME}") {
withCredentials([sshUserPrivateKey(credentialsId: "${env.GIT_SSH_KEY_ID}", keyFileVariable: 'SSH_KEY', usernameVariable: 'SSH_USER')]) {
withEnv(["GIT_SSH_COMMAND=ssh -i ${SSH_KEY}"]) {
sh '''
git config user.email "${SSH_USER}@XXX.com"
git config user.name "${SSH_USER}"
# backup only keep the lastest X backup-files
ls -tp ${BACKUP_PREFIX_NAME}_*.tar.gz | grep -v '/$' | tail -n +$(expr ${NUMBER_OF_BACKUPS} + 1) | xargs -I {} rm -- {}
# Push to git
git add --all
git status
git commit --amend -CHEAD --allow-empty
git push --force-with-lease origin master
env
'''
}
}
}
}
}
}
post {
failure {
hangoutsNotify message: "${JOB_BASE_NAME} faild!",token: "${env.GOOGLE_CHAT_TOKEN}",threadByJob: true
}
}
}
Groovy 脚本“safe_backup_run.groovy”:
import hudson.model.RestartListener
import jenkins.model.*;
//backup method
def jenkins_safe_backup(job_name) {
//set the
if(!binding.hasVariable('timeout_seconds')) {
timeout_seconds = 60
}
if(timeout_seconds in String) {
timeout_seconds = Integer.decode(timeout_seconds)
}
//type check user defined parameters/bindings
if(!(timeout_seconds in Integer)) {
throw new Exception('PARAMETER ERROR: timeout_seconds must be an integer.')
}
print("Jenkins safe backup initiated.")
while(true) {
//get the list of all the currenty running jobs
runningBuilds = Jenkins.instance.getView('All').getBuilds().findAll() { it.getResult().equals(null) }
//remove the 'Jenkins_Backup' job from the list
runningBuilds.removeAll { it.toString().toLowerCase().startsWith(job_name.toLowerCase()) }
//get the list of queued jobs
def queuedBuilds = []
Jenkins.instance.queue.items.findAll { queuedBuilds.add(it.task.name) }
//remove the 'Jenkins_Backup' job from the list
queuedBuilds.removeAll { it.toString().toLowerCase().startsWith(job_name.toLowerCase()) }
//If no job is running except 'Jenkins_Backup' break
if((runningBuilds.isEmpty()) && (queuedBuilds.isEmpty())) {
break
}
print("Jenkins jobs/queue are not idle. Waiting ${timeout_seconds} seconds before next backup attempt.")
print("RUNNING jobs: " + runningBuilds)
print("QUEUED jobs: " + queuedBuilds)
sleep(timeout_seconds)
}
}
return this
推荐阅读
- java - 使用 java 8 并行处理图像
- python - VSC - Python - 错误的识别级别
- r - 从 R 中的 n 长度向量和 m 长度向量生成 nxm 矩阵
- java - Spring Boot 更新用户数据的最佳方法是什么?
- vba - 如何在 VBA 中循环查找对话框
- reactjs - 组件即使在状态突变 redux 下也能工作
- javascript - 解析 json 数组并遍历 Pivot.js 的所有数据
- php - 在 MySQL 中添加用户的多个收藏夹
- python - 为 Raspberry Pi 使用 Google 的语音到文本 API
- css - Flexbox - 响应式缩小