Skip to content

Instantly share code, notes, and snippets.

@taherbs
Last active September 19, 2024 13:48
Show Gist options
  • Save taherbs/6d03b4d56ac4f1e7a119e64cf5d17f4c to your computer and use it in GitHub Desktop.
Save taherbs/6d03b4d56ac4f1e7a119e64cf5d17f4c to your computer and use it in GitHub Desktop.
jenkins safe auto update plugins
//List all active plugins and save them into a file
def list_jenkins_plugins(directory, fileName) {
File pluginsListFile = new File("$directory/$fileName")
jenkins.model.Jenkins.instance.pluginManager.activePlugins.findAll { plugin ->
pluginsListFile.append("${plugin.getDisplayName()} (${plugin.getShortName()}): ${plugin.getVersion()}" + System.getProperty("line.separator"))
}
}
//Perform jenkins plugin update in a safe manner
def jenkins_safe_plugins_update() {
//Refresh plugins updates list
jenkins.model.Jenkins.getInstanceOrNull().getUpdateCenter().getSites().each { site ->
site.updateDirectlyNow(hudson.model.DownloadService.signatureCheck)
}
hudson.model.DownloadService.Downloadable.all().each { downloadable ->
downloadable.updateNow();
}
//Get the list of plugins
def pluginsToUpdate = []
def pluginsToReviewManually = []
def pluginsDeprecated = []
jenkins.model.Jenkins.instance.pluginManager.activePlugins.findAll { plugin ->
if (!(plugin.getDeprecations().isEmpty())) {
pluginsDeprecated.add(plugin.getDisplayName())
} else if (plugin.hasUpdate()) {
if (plugin.getActiveWarnings().isEmpty()) {
pluginsToUpdate.add(plugin.getShortName())
}
else {
pluginsToReviewManually.add(plugin.getDisplayName())
}
}
}
println "Plugins to upgrade automatically: ${pluginsToUpdate}"
println "Plugins to review and update manually: ${pluginsToReviewManually}"
println "Plugins depricated: ${pluginsDeprecated}"
long count = 0
jenkins.model.Jenkins.instance.pluginManager.install(pluginsToUpdate, false).each { f ->
f.get()
println "${++count}/${pluginsToUpdate.size()}.."
}
if(pluginsToUpdate.size() != 0 && count == pluginsToUpdate.size()) {
jenkins.model.Jenkins.instance.safeRestart()
}
return [ pluginsToReviewManually, pluginsDeprecated ]
}
return this
def DATETIME = new Date().format('yyyy_MM_dd_HH_mm_ss', TimeZone.getTimeZone('Canada/Eastern'))
def pluginsToReviewManually = []
def pluginsDeprecated = []
pipeline {
agent { label 'master' }
options {
//Build options
disableConcurrentBuilds()
buildDiscarder(
logRotator (
artifactDaysToKeepStr: '10',
artifactNumToKeepStr: '1',
daysToKeepStr: '30',
numToKeepStr: '30'
)
)
}
triggers { cron('TZ=Canada/Eastern\n0 0 * * 7') }
environment {
GOOGLE_CHAT_TOKEN = 'XXX-XXX-XXX-XXX'
}
stages {
stage('Update_Plugins') {
steps {
script {
def safePluginUpdateModule = load("${WORKSPACE}/jenkins_auto_update_plugins/jenkins-plugins-uptodate.groovy")
safePluginUpdateModule.list_jenkins_plugins("${WORKSPACE}/jenkins_auto_update_plugins", "plugins_list_BEFORE-UPDATE_${DATETIME}.txt")
(pluginsToReviewManually, pluginsDeprecated) = safePluginUpdateModule.jenkins_safe_plugins_update()
safePluginUpdateModule.list_jenkins_plugins("${WORKSPACE}/jenkins_auto_update_plugins", "plugins_list_AFTER-UPDATE_${DATETIME}.txt")
}
}
}
}
post {
always {
script {
archiveArtifacts "jenkins_auto_update_plugins/plugins_list_*_${DATETIME}.txt"
if (!(pluginsToReviewManually.isEmpty())) {
hangoutsNotify message: "IMPORTANT!!! The following plugins need to get reviewed and updated manually: ${pluginsToReviewManually}",token: "${env.GOOGLE_CHAT_TOKEN}",threadByJob: true
} else if (!(pluginsDeprecated.isEmpty())) {
hangoutsNotify message: "IMPORTANT!!! The following plugins are deprecated and need to be deleted: ${pluginsDeprecated}",token: "${env.GOOGLE_CHAT_TOKEN}",threadByJob: true
}
}
}
failure {
hangoutsNotify message: "${JOB_BASE_NAME} faild!",token: "${env.GOOGLE_CHAT_TOKEN}",threadByJob: true
}
}
}
@raphperrin
Copy link

Hey @taherbs
By any chance did you implement a compatibility check ? In my case it updated all plugins even the one with warning and "not compatible".

@taherbs
Copy link
Author

taherbs commented Dec 7, 2021

@radnov did not look into that use case for the moment.
@raphperrin I have those 2 checks:

plugin.getActiveWarnings() -> to check if we have warning
plugin.getDeprecations() -> check if the plugin got deprecated

if we hit one of those conditions a notificatation get sent and a manual review is required, I did not find a way to fully automate that part

@vvursT
Copy link

vvursT commented Mar 8, 2022

Thank you for providing this useful script. We use the plugin Script-Security which is complaining all the insecure methods that are used in this script. Do you know any other way to approve script security instead of whitelisting all method calls? Thank you in advice.

@romancin
Copy link

romancin commented Nov 4, 2022

Thank you very much for this!!

Here you have the list of signatures used by this script you need to approve:

field hudson.PluginManager activePlugins
method hudson.PluginManager install java.util.Collection boolean
method hudson.PluginWrapper getActiveWarnings
method hudson.PluginWrapper getDeprecations
method hudson.PluginWrapper getShortName
method hudson.PluginWrapper getVersion
method hudson.PluginWrapper hasUpdate
method hudson.model.DownloadService$Downloadable updateNow
method hudson.model.UpdateCenter getSites
method hudson.model.UpdateSite updateDirectlyNow boolean
method java.util.concurrent.Future get
method jenkins.model.Jenkins getPluginManager
method jenkins.model.Jenkins getUpdateCenter
method jenkins.model.Jenkins safeRestart
new java.io.File java.lang.String
staticField hudson.model.DownloadService signatureCheck
staticMethod hudson.model.DownloadService$Downloadable all
staticMethod java.lang.System getProperty java.lang.String
staticMethod jenkins.model.Jenkins getInstance
staticMethod jenkins.model.Jenkins getInstanceOrNull
staticMethod org.codehaus.groovy.runtime.DefaultGroovyMethods append java.io.File java.lang.Object

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment