Carlos Sanchez | 7d165ac | 2016-08-14 11:13:12 +0200 | [diff] [blame] | 1 | #!/bin/bash -eu |
Nicolas De Loof | 0ef5a62 | 2016-05-27 19:14:29 +0200 | [diff] [blame] | 2 | |
Sýlvan Heuser | b20f388 | 2016-06-01 15:47:38 +0200 | [diff] [blame] | 3 | # Resolve dependencies and download plugins given on the command line |
| 4 | # |
| 5 | # FROM jenkins |
| 6 | # RUN install-plugins.sh docker-slaves github-branch-source |
| 7 | |
Carlos Sanchez | 3a83b9d | 2016-08-08 09:36:28 +0200 | [diff] [blame] | 8 | set -o pipefail |
| 9 | |
apottere | bbd13d0 | 2016-06-23 12:24:15 -0400 | [diff] [blame] | 10 | REF_DIR=${REF:-/usr/share/jenkins/ref/plugins} |
Denis Egorenko | 6ddff32 | 2018-11-08 16:44:02 +0400 | [diff] [blame] | 11 | DEPS_PINNING_FILE=${DEPS_PINNING_FILE:-/usr/share/jenkins/ref/jenkins-plugins-deps} |
apottere | bbd13d0 | 2016-06-23 12:24:15 -0400 | [diff] [blame] | 12 | FAILED="$REF_DIR/failed-plugins.txt" |
Sýlvan Heuser | b20f388 | 2016-06-01 15:47:38 +0200 | [diff] [blame] | 13 | |
Vincent Latombe | c14af95 | 2016-07-18 10:20:12 +0200 | [diff] [blame] | 14 | . /usr/local/bin/jenkins-support |
| 15 | |
Charles Duffy | 3eec42c | 2016-09-20 12:11:33 -0500 | [diff] [blame] | 16 | getLockFile() { |
| 17 | printf '%s' "$REF_DIR/${1}.lock" |
apottere | bbd13d0 | 2016-06-23 12:24:15 -0400 | [diff] [blame] | 18 | } |
| 19 | |
Charles Duffy | 3eec42c | 2016-09-20 12:11:33 -0500 | [diff] [blame] | 20 | getArchiveFilename() { |
| 21 | printf '%s' "$REF_DIR/${1}.jpi" |
apottere | bbd13d0 | 2016-06-23 12:24:15 -0400 | [diff] [blame] | 22 | } |
Sýlvan Heuser | b20f388 | 2016-06-01 15:47:38 +0200 | [diff] [blame] | 23 | |
Charles Duffy | 3eec42c | 2016-09-20 12:11:33 -0500 | [diff] [blame] | 24 | download() { |
Carlos Sanchez | c0f6379 | 2016-08-15 10:30:16 +0200 | [diff] [blame] | 25 | local plugin originalPlugin version lock ignoreLockFile |
| 26 | plugin="$1" |
| 27 | version="${2:-latest}" |
| 28 | ignoreLockFile="${3:-}" |
| 29 | lock="$(getLockFile "$plugin")" |
Nicolas De Loof | 0ef5a62 | 2016-05-27 19:14:29 +0200 | [diff] [blame] | 30 | |
Carlos Sanchez | c0f6379 | 2016-08-15 10:30:16 +0200 | [diff] [blame] | 31 | if [[ $ignoreLockFile ]] || mkdir "$lock" &>/dev/null; then |
| 32 | if ! doDownload "$plugin" "$version"; then |
| 33 | # some plugin don't follow the rules about artifact ID |
| 34 | # typically: docker-plugin |
| 35 | originalPlugin="$plugin" |
| 36 | plugin="${plugin}-plugin" |
| 37 | if ! doDownload "$plugin" "$version"; then |
| 38 | echo "Failed to download plugin: $originalPlugin or $plugin" >&2 |
| 39 | echo "Not downloaded: ${originalPlugin}" >> "$FAILED" |
| 40 | return 1 |
| 41 | fi |
| 42 | fi |
Nicolas De Loof | a7a34c3 | 2016-05-30 09:10:58 +0200 | [diff] [blame] | 43 | |
Carlos Sanchez | c0f6379 | 2016-08-15 10:30:16 +0200 | [diff] [blame] | 44 | if ! checkIntegrity "$plugin"; then |
| 45 | echo "Downloaded file is not a valid ZIP: $(getArchiveFilename "$plugin")" >&2 |
| 46 | echo "Download integrity: ${plugin}" >> "$FAILED" |
| 47 | return 1 |
| 48 | fi |
apottere | bbd13d0 | 2016-06-23 12:24:15 -0400 | [diff] [blame] | 49 | |
Carlos Sanchez | c0f6379 | 2016-08-15 10:30:16 +0200 | [diff] [blame] | 50 | resolveDependencies "$plugin" |
| 51 | fi |
Nicolas De Loof | 0ef5a62 | 2016-05-27 19:14:29 +0200 | [diff] [blame] | 52 | } |
| 53 | |
Charles Duffy | 3eec42c | 2016-09-20 12:11:33 -0500 | [diff] [blame] | 54 | doDownload() { |
Carlos Sanchez | c0f6379 | 2016-08-15 10:30:16 +0200 | [diff] [blame] | 55 | local plugin version url jpi |
| 56 | plugin="$1" |
| 57 | version="$2" |
| 58 | jpi="$(getArchiveFilename "$plugin")" |
apottere | bbd13d0 | 2016-06-23 12:24:15 -0400 | [diff] [blame] | 59 | |
Carlos Sanchez | c0f6379 | 2016-08-15 10:30:16 +0200 | [diff] [blame] | 60 | # If plugin already exists and is the same version do not download |
| 61 | if test -f "$jpi" && unzip -p "$jpi" META-INF/MANIFEST.MF | tr -d '\r' | grep "^Plugin-Version: ${version}$" > /dev/null; then |
| 62 | echo "Using provided plugin: $plugin" |
| 63 | return 0 |
| 64 | fi |
apottere | bbd13d0 | 2016-06-23 12:24:15 -0400 | [diff] [blame] | 65 | |
Carlos Sanchez | 0d167af | 2016-08-29 11:02:57 +0200 | [diff] [blame] | 66 | JENKINS_UC_DOWNLOAD=${JENKINS_UC_DOWNLOAD:-"$JENKINS_UC/download"} |
Jean-Louis Boudart | ad0ff9c | 2016-08-22 09:00:30 +0200 | [diff] [blame] | 67 | |
| 68 | url="$JENKINS_UC_DOWNLOAD/plugins/$plugin/$version/${plugin}.hpi" |
apottere | bbd13d0 | 2016-06-23 12:24:15 -0400 | [diff] [blame] | 69 | |
Carlos Sanchez | c0f6379 | 2016-08-15 10:30:16 +0200 | [diff] [blame] | 70 | echo "Downloading plugin: $plugin from $url" |
Carlos Sanchez | 21b0f37 | 2016-10-06 13:26:17 -0700 | [diff] [blame] | 71 | curl --connect-timeout ${CURL_CONNECTION_TIMEOUT:-20} --retry ${CURL_RETRY:-5} --retry-delay ${CURL_RETRY_DELAY:-0} --retry-max-time ${CURL_RETRY_MAX_TIME:-60} -s -f -L "$url" -o "$jpi" |
Carlos Sanchez | c0f6379 | 2016-08-15 10:30:16 +0200 | [diff] [blame] | 72 | return $? |
apottere | bbd13d0 | 2016-06-23 12:24:15 -0400 | [diff] [blame] | 73 | } |
| 74 | |
Charles Duffy | 3eec42c | 2016-09-20 12:11:33 -0500 | [diff] [blame] | 75 | checkIntegrity() { |
Carlos Sanchez | c0f6379 | 2016-08-15 10:30:16 +0200 | [diff] [blame] | 76 | local plugin jpi |
| 77 | plugin="$1" |
| 78 | jpi="$(getArchiveFilename "$plugin")" |
apottere | bbd13d0 | 2016-06-23 12:24:15 -0400 | [diff] [blame] | 79 | |
Gareth Harcombe-Minson | d6a7512 | 2016-09-26 09:59:36 -0500 | [diff] [blame] | 80 | unzip -t -qq "$jpi" >/dev/null |
Carlos Sanchez | c0f6379 | 2016-08-15 10:30:16 +0200 | [diff] [blame] | 81 | return $? |
apottere | bbd13d0 | 2016-06-23 12:24:15 -0400 | [diff] [blame] | 82 | } |
| 83 | |
Denis Egorenko | 6ddff32 | 2018-11-08 16:44:02 +0400 | [diff] [blame] | 84 | getPluginDepsPinnedVersion() { |
| 85 | local plugin |
| 86 | plugin="$1" |
| 87 | pinnedPlugin=$(cat $DEPS_PINNING_FILE | grep "^${plugin}:") |
| 88 | if [ -n "$pinnedPlugin" ]; then |
| 89 | pinnedPluginVersion="$(echo "$pinnedPlugin" | cut -d':' -f2 | tr -d ' ')" |
| 90 | printf '%s' "$pinnedPluginVersion" |
| 91 | fi |
| 92 | } |
| 93 | |
Charles Duffy | 3eec42c | 2016-09-20 12:11:33 -0500 | [diff] [blame] | 94 | resolveDependencies() { |
Carlos Sanchez | c0f6379 | 2016-08-15 10:30:16 +0200 | [diff] [blame] | 95 | local plugin jpi dependencies |
| 96 | plugin="$1" |
| 97 | jpi="$(getArchiveFilename "$plugin")" |
Nicolas De Loof | 0ef5a62 | 2016-05-27 19:14:29 +0200 | [diff] [blame] | 98 | |
Carlos Sanchez | c0f6379 | 2016-08-15 10:30:16 +0200 | [diff] [blame] | 99 | dependencies="$(unzip -p "$jpi" META-INF/MANIFEST.MF | tr -d '\r' | tr '\n' '|' | sed -e 's#| ##g' | tr '|' '\n' | grep "^Plugin-Dependencies: " | sed -e 's#^Plugin-Dependencies: ##')" |
Nicolas De Loof | 0ef5a62 | 2016-05-27 19:14:29 +0200 | [diff] [blame] | 100 | |
Carlos Sanchez | c0f6379 | 2016-08-15 10:30:16 +0200 | [diff] [blame] | 101 | if [[ ! $dependencies ]]; then |
| 102 | echo " > $plugin has no dependencies" |
| 103 | return |
| 104 | fi |
Nicolas De Loof | 0ef5a62 | 2016-05-27 19:14:29 +0200 | [diff] [blame] | 105 | |
Carlos Sanchez | c0f6379 | 2016-08-15 10:30:16 +0200 | [diff] [blame] | 106 | echo " > $plugin depends on $dependencies" |
Nicolas De Loof | 0ef5a62 | 2016-05-27 19:14:29 +0200 | [diff] [blame] | 107 | |
Charles Duffy | 3eec42c | 2016-09-20 12:11:33 -0500 | [diff] [blame] | 108 | IFS=',' read -r -a array <<< "$dependencies" |
apottere | bbd13d0 | 2016-06-23 12:24:15 -0400 | [diff] [blame] | 109 | |
Carlos Sanchez | c0f6379 | 2016-08-15 10:30:16 +0200 | [diff] [blame] | 110 | for d in "${array[@]}" |
| 111 | do |
| 112 | plugin="$(cut -d':' -f1 - <<< "$d")" |
| 113 | if [[ $d == *"resolution:=optional"* ]]; then |
| 114 | echo "Skipping optional dependency $plugin" |
| 115 | else |
| 116 | local pluginInstalled |
Denis Egorenko | 6ddff32 | 2018-11-08 16:44:02 +0400 | [diff] [blame] | 117 | local pluginVersion; pluginVersion=$(getPluginDepsPinnedVersion "${plugin}") |
Carlos Sanchez | c0f6379 | 2016-08-15 10:30:16 +0200 | [diff] [blame] | 118 | if pluginInstalled="$(echo "${bundledPlugins}" | grep "^${plugin}:")"; then |
| 119 | pluginInstalled="${pluginInstalled//[$'\r']}" |
| 120 | local versionInstalled; versionInstalled=$(versionFromPlugin "${pluginInstalled}") |
Denis Egorenko | 6ddff32 | 2018-11-08 16:44:02 +0400 | [diff] [blame] | 121 | local minVersion="$pluginVersion" |
| 122 | if [ -z "$minVersion" ]; then |
| 123 | minVersion=$(versionFromPlugin "${d}") |
| 124 | fi |
Carlos Sanchez | 119703c | 2016-08-15 10:59:54 +0200 | [diff] [blame] | 125 | if versionLT "${versionInstalled}" "${minVersion}"; then |
| 126 | echo "Upgrading bundled dependency $d ($minVersion > $versionInstalled)" |
Denis Egorenko | 6ddff32 | 2018-11-08 16:44:02 +0400 | [diff] [blame] | 127 | download "$plugin" "$pluginVersion" & |
Carlos Sanchez | c0f6379 | 2016-08-15 10:30:16 +0200 | [diff] [blame] | 128 | else |
Carlos Sanchez | 119703c | 2016-08-15 10:59:54 +0200 | [diff] [blame] | 129 | echo "Skipping already bundled dependency $d ($minVersion <= $versionInstalled)" |
Carlos Sanchez | c0f6379 | 2016-08-15 10:30:16 +0200 | [diff] [blame] | 130 | fi |
| 131 | else |
Denis Egorenko | 6ddff32 | 2018-11-08 16:44:02 +0400 | [diff] [blame] | 132 | download "$plugin" "$pluginVersion" & |
Carlos Sanchez | c0f6379 | 2016-08-15 10:30:16 +0200 | [diff] [blame] | 133 | fi |
| 134 | fi |
| 135 | done |
| 136 | wait |
Nicolas De Loof | 0ef5a62 | 2016-05-27 19:14:29 +0200 | [diff] [blame] | 137 | } |
| 138 | |
Charles Duffy | 3eec42c | 2016-09-20 12:11:33 -0500 | [diff] [blame] | 139 | bundledPlugins() { |
Carlos Sanchez | c0f6379 | 2016-08-15 10:30:16 +0200 | [diff] [blame] | 140 | local JENKINS_WAR=/usr/share/jenkins/jenkins.war |
| 141 | if [ -f $JENKINS_WAR ] |
| 142 | then |
| 143 | TEMP_PLUGIN_DIR=/tmp/plugintemp.$$ |
| 144 | for i in $(jar tf $JENKINS_WAR | egrep '[^detached-]plugins.*\..pi' | sort) |
| 145 | do |
| 146 | rm -fr $TEMP_PLUGIN_DIR |
| 147 | mkdir -p $TEMP_PLUGIN_DIR |
| 148 | PLUGIN=$(basename "$i"|cut -f1 -d'.') |
| 149 | (cd $TEMP_PLUGIN_DIR;jar xf "$JENKINS_WAR" "$i";jar xvf "$TEMP_PLUGIN_DIR/$i" META-INF/MANIFEST.MF >/dev/null 2>&1) |
| 150 | VER=$(egrep -i Plugin-Version "$TEMP_PLUGIN_DIR/META-INF/MANIFEST.MF"|cut -d: -f2|sed 's/ //') |
| 151 | echo "$PLUGIN:$VER" |
| 152 | done |
| 153 | rm -fr $TEMP_PLUGIN_DIR |
| 154 | else |
| 155 | rm -f "$TEMP_ALREADY_INSTALLED" |
| 156 | echo "ERROR file not found: $JENKINS_WAR" |
| 157 | exit 1 |
| 158 | fi |
Carlos Sanchez | e1b99f4 | 2016-07-06 14:22:39 +0200 | [diff] [blame] | 159 | } |
| 160 | |
Charles Duffy | 3eec42c | 2016-09-20 12:11:33 -0500 | [diff] [blame] | 161 | versionFromPlugin() { |
Carlos Sanchez | c0f6379 | 2016-08-15 10:30:16 +0200 | [diff] [blame] | 162 | local plugin=$1 |
| 163 | if [[ $plugin =~ .*:.* ]]; then |
| 164 | echo "${plugin##*:}" |
| 165 | else |
| 166 | echo "latest" |
| 167 | fi |
Carlos Sanchez | e1b99f4 | 2016-07-06 14:22:39 +0200 | [diff] [blame] | 168 | |
| 169 | } |
| 170 | |
Charles Duffy | 3eec42c | 2016-09-20 12:11:33 -0500 | [diff] [blame] | 171 | installedPlugins() { |
Carlos Sanchez | b5ae0c5 | 2016-08-15 11:38:24 +0200 | [diff] [blame] | 172 | for f in "$REF_DIR"/*.jpi; do |
| 173 | echo "$(basename "$f" | sed -e 's/\.jpi//'):$(get_plugin_version "$f")" |
| 174 | done |
| 175 | } |
| 176 | |
apottere | bbd13d0 | 2016-06-23 12:24:15 -0400 | [diff] [blame] | 177 | main() { |
Carlos Sanchez | c0f6379 | 2016-08-15 10:30:16 +0200 | [diff] [blame] | 178 | local plugin version |
Sýlvan Heuser | b20f388 | 2016-06-01 15:47:38 +0200 | [diff] [blame] | 179 | |
Carlos Sanchez | c0f6379 | 2016-08-15 10:30:16 +0200 | [diff] [blame] | 180 | mkdir -p "$REF_DIR" || exit 1 |
Nicolas De Loof | a7a34c3 | 2016-05-30 09:10:58 +0200 | [diff] [blame] | 181 | |
Carlos Sanchez | c0f6379 | 2016-08-15 10:30:16 +0200 | [diff] [blame] | 182 | # Create lockfile manually before first run to make sure any explicit version set is used. |
| 183 | echo "Creating initial locks..." |
| 184 | for plugin in "$@"; do |
| 185 | mkdir "$(getLockFile "${plugin%%:*}")" |
| 186 | done |
apottere | bbd13d0 | 2016-06-23 12:24:15 -0400 | [diff] [blame] | 187 | |
Carlos Sanchez | 2fb0684 | 2016-10-06 14:13:05 -0700 | [diff] [blame] | 188 | echo "Analyzing war..." |
Carlos Sanchez | c0f6379 | 2016-08-15 10:30:16 +0200 | [diff] [blame] | 189 | bundledPlugins="$(bundledPlugins)" |
Carlos Sanchez | e1b99f4 | 2016-07-06 14:22:39 +0200 | [diff] [blame] | 190 | |
Carlos Sanchez | 2fb0684 | 2016-10-06 14:13:05 -0700 | [diff] [blame] | 191 | echo "Downloading plugins..." |
Carlos Sanchez | c0f6379 | 2016-08-15 10:30:16 +0200 | [diff] [blame] | 192 | for plugin in "$@"; do |
| 193 | version="" |
apottere | bbd13d0 | 2016-06-23 12:24:15 -0400 | [diff] [blame] | 194 | |
Carlos Sanchez | c0f6379 | 2016-08-15 10:30:16 +0200 | [diff] [blame] | 195 | if [[ $plugin =~ .*:.* ]]; then |
| 196 | version=$(versionFromPlugin "${plugin}") |
| 197 | plugin="${plugin%%:*}" |
| 198 | fi |
apottere | bbd13d0 | 2016-06-23 12:24:15 -0400 | [diff] [blame] | 199 | |
Carlos Sanchez | c0f6379 | 2016-08-15 10:30:16 +0200 | [diff] [blame] | 200 | download "$plugin" "$version" "true" & |
| 201 | done |
| 202 | wait |
apottere | bbd13d0 | 2016-06-23 12:24:15 -0400 | [diff] [blame] | 203 | |
Carlos Sanchez | b5ae0c5 | 2016-08-15 11:38:24 +0200 | [diff] [blame] | 204 | echo |
| 205 | echo "WAR bundled plugins:" |
| 206 | echo "${bundledPlugins}" |
| 207 | echo |
| 208 | echo "Installed plugins:" |
| 209 | installedPlugins |
| 210 | |
Carlos Sanchez | c0f6379 | 2016-08-15 10:30:16 +0200 | [diff] [blame] | 211 | if [[ -f $FAILED ]]; then |
Carlos Sanchez | 2fb0684 | 2016-10-06 14:13:05 -0700 | [diff] [blame] | 212 | echo "Some plugins failed to download!" "$(<"$FAILED")" >&2 |
Carlos Sanchez | c0f6379 | 2016-08-15 10:30:16 +0200 | [diff] [blame] | 213 | exit 1 |
| 214 | fi |
apottere | bbd13d0 | 2016-06-23 12:24:15 -0400 | [diff] [blame] | 215 | |
Carlos Sanchez | 2fb0684 | 2016-10-06 14:13:05 -0700 | [diff] [blame] | 216 | echo "Cleaning up locks" |
Carlos Sanchez | c0f6379 | 2016-08-15 10:30:16 +0200 | [diff] [blame] | 217 | rm -r "$REF_DIR"/*.lock |
apottere | bbd13d0 | 2016-06-23 12:24:15 -0400 | [diff] [blame] | 218 | } |
| 219 | |
Brian Antonelli | 6706b26 | 2016-06-24 06:31:54 -0400 | [diff] [blame] | 220 | main "$@" |