install-plugins.sh 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. #!/bin/bash -eu
  2. # Resolve dependencies and download plugins given on the command line
  3. #
  4. # FROM jenkins
  5. # RUN install-plugins.sh docker-slaves github-branch-source
  6. set -o pipefail
  7. REF_DIR=${REF:-/usr/share/jenkins/ref/plugins}
  8. FAILED="$REF_DIR/failed-plugins.txt"
  9. . /usr/local/bin/jenkins-support
  10. getLockFile() {
  11. printf '%s' "$REF_DIR/${1}.lock"
  12. }
  13. getArchiveFilename() {
  14. printf '%s' "$REF_DIR/${1}.jpi"
  15. }
  16. download() {
  17. local plugin originalPlugin version lock ignoreLockFile
  18. plugin="$1"
  19. version="${2:-latest}"
  20. ignoreLockFile="${3:-}"
  21. lock="$(getLockFile "$plugin")"
  22. if [[ $ignoreLockFile ]] || mkdir "$lock" &>/dev/null; then
  23. if ! doDownload "$plugin" "$version"; then
  24. # some plugin don't follow the rules about artifact ID
  25. # typically: docker-plugin
  26. originalPlugin="$plugin"
  27. plugin="${plugin}-plugin"
  28. if ! doDownload "$plugin" "$version"; then
  29. echo "Failed to download plugin: $originalPlugin or $plugin" >&2
  30. echo "Not downloaded: ${originalPlugin}" >> "$FAILED"
  31. return 1
  32. fi
  33. fi
  34. if ! checkIntegrity "$plugin"; then
  35. echo "Downloaded file is not a valid ZIP: $(getArchiveFilename "$plugin")" >&2
  36. echo "Download integrity: ${plugin}" >> "$FAILED"
  37. return 1
  38. fi
  39. resolveDependencies "$plugin"
  40. fi
  41. }
  42. doDownload() {
  43. local plugin version url jpi
  44. plugin="$1"
  45. version="$2"
  46. jpi="$(getArchiveFilename "$plugin")"
  47. # If plugin already exists and is the same version do not download
  48. if test -f "$jpi" && unzip -p "$jpi" META-INF/MANIFEST.MF | tr -d '\r' | grep "^Plugin-Version: ${version}$" > /dev/null; then
  49. echo "Using provided plugin: $plugin"
  50. return 0
  51. fi
  52. JENKINS_UC_DOWNLOAD=${JENKINS_UC_DOWNLOAD:-"$JENKINS_UC/download"}
  53. url="$JENKINS_UC_DOWNLOAD/plugins/$plugin/$version/${plugin}.hpi"
  54. echo "Downloading plugin: $plugin from $url"
  55. 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"
  56. return $?
  57. }
  58. checkIntegrity() {
  59. local plugin jpi
  60. plugin="$1"
  61. jpi="$(getArchiveFilename "$plugin")"
  62. unzip -t -qq "$jpi" >/dev/null
  63. return $?
  64. }
  65. resolveDependencies() {
  66. local plugin jpi dependencies
  67. plugin="$1"
  68. jpi="$(getArchiveFilename "$plugin")"
  69. 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: ##')"
  70. if [[ ! $dependencies ]]; then
  71. echo " > $plugin has no dependencies"
  72. return
  73. fi
  74. echo " > $plugin depends on $dependencies"
  75. IFS=',' read -r -a array <<< "$dependencies"
  76. for d in "${array[@]}"
  77. do
  78. plugin="$(cut -d':' -f1 - <<< "$d")"
  79. if [[ $d == *"resolution:=optional"* ]]; then
  80. echo "Skipping optional dependency $plugin"
  81. else
  82. local pluginInstalled
  83. if pluginInstalled="$(echo "${bundledPlugins}" | grep "^${plugin}:")"; then
  84. pluginInstalled="${pluginInstalled//[$'\r']}"
  85. local versionInstalled; versionInstalled=$(versionFromPlugin "${pluginInstalled}")
  86. local minVersion; minVersion=$(versionFromPlugin "${d}")
  87. if versionLT "${versionInstalled}" "${minVersion}"; then
  88. echo "Upgrading bundled dependency $d ($minVersion > $versionInstalled)"
  89. download "$plugin" &
  90. else
  91. echo "Skipping already bundled dependency $d ($minVersion <= $versionInstalled)"
  92. fi
  93. else
  94. download "$plugin" &
  95. fi
  96. fi
  97. done
  98. wait
  99. }
  100. bundledPlugins() {
  101. local JENKINS_WAR=/usr/share/jenkins/jenkins.war
  102. if [ -f $JENKINS_WAR ]
  103. then
  104. TEMP_PLUGIN_DIR=/tmp/plugintemp.$$
  105. for i in $(jar tf $JENKINS_WAR | egrep '[^detached-]plugins.*\..pi' | sort)
  106. do
  107. rm -fr $TEMP_PLUGIN_DIR
  108. mkdir -p $TEMP_PLUGIN_DIR
  109. PLUGIN=$(basename "$i"|cut -f1 -d'.')
  110. (cd $TEMP_PLUGIN_DIR;jar xf "$JENKINS_WAR" "$i";jar xvf "$TEMP_PLUGIN_DIR/$i" META-INF/MANIFEST.MF >/dev/null 2>&1)
  111. VER=$(egrep -i Plugin-Version "$TEMP_PLUGIN_DIR/META-INF/MANIFEST.MF"|cut -d: -f2|sed 's/ //')
  112. echo "$PLUGIN:$VER"
  113. done
  114. rm -fr $TEMP_PLUGIN_DIR
  115. else
  116. rm -f "$TEMP_ALREADY_INSTALLED"
  117. echo "ERROR file not found: $JENKINS_WAR"
  118. exit 1
  119. fi
  120. }
  121. versionFromPlugin() {
  122. local plugin=$1
  123. if [[ $plugin =~ .*:.* ]]; then
  124. echo "${plugin##*:}"
  125. else
  126. echo "latest"
  127. fi
  128. }
  129. installedPlugins() {
  130. for f in "$REF_DIR"/*.jpi; do
  131. echo "$(basename "$f" | sed -e 's/\.jpi//'):$(get_plugin_version "$f")"
  132. done
  133. }
  134. main() {
  135. local plugin version
  136. mkdir -p "$REF_DIR" || exit 1
  137. # Create lockfile manually before first run to make sure any explicit version set is used.
  138. echo "Creating initial locks..."
  139. for plugin in "$@"; do
  140. mkdir "$(getLockFile "${plugin%%:*}")"
  141. done
  142. echo "Analyzing war..."
  143. bundledPlugins="$(bundledPlugins)"
  144. echo "Downloading plugins..."
  145. for plugin in "$@"; do
  146. version=""
  147. if [[ $plugin =~ .*:.* ]]; then
  148. version=$(versionFromPlugin "${plugin}")
  149. plugin="${plugin%%:*}"
  150. fi
  151. download "$plugin" "$version" "true" &
  152. done
  153. wait
  154. echo
  155. echo "WAR bundled plugins:"
  156. echo "${bundledPlugins}"
  157. echo
  158. echo "Installed plugins:"
  159. installedPlugins
  160. if [[ -f $FAILED ]]; then
  161. echo "Some plugins failed to download!" "$(<"$FAILED")" >&2
  162. exit 1
  163. fi
  164. echo "Cleaning up locks"
  165. rm -r "$REF_DIR"/*.lock
  166. }
  167. main "$@"