Upgrade plugins if needed (#306)
Each plugin installed through the docker image is now tracked using a
marker file containing the version that was installed through the image.
If later, the container is started from a docker image containing newer
plugins, existing plugins will be upgraded if they haven't been upgraded
in the mean time and if the new docker image provides a new version of
them.
Add tests to check that plugins are upgrade properly
diff --git a/README.md b/README.md
index 72114e2..3dc4499 100644
--- a/README.md
+++ b/README.md
@@ -223,6 +223,12 @@
As always - please ensure that you know how to drive docker - especially volume handling!
+## Upgrading plugins
+
+By default, plugins will be upgraded if they haven't been upgraded manually and if the version from the docker image is newer than the version in the container. Versions installed by the docker image are tracked through a marker file.
+
+The default behaviour when upgrading from a docker image that didn't write marker files is to leave existing plugins in place. If you want to upgrade existing plugins without marker you may run the docker image with `-e TRY_UPGRADE_IF_NO_MARKER=true`. Then plugins will be upgraded if the version provided by the docker image is newer.
+
# Building
Build with the usual
diff --git a/jenkins.sh b/jenkins.sh
index 2fa42cd..570f1c8 100755
--- a/jenkins.sh
+++ b/jenkins.sh
@@ -2,6 +2,19 @@
set -e
+# compare if version1 < version2
+versionLT() {
+ [ "$1" = "$2" ] && return 1 || [ "$1" = "`echo -e "$1\n$2" | sort -V | head -n1`" ]
+}
+
+# returns a plugin version from a plugin archive
+get_plugin_version() {
+ local archive; archive=$1
+ local version; version=$(unzip -p $archive META-INF/MANIFEST.MF | grep "^Plugin-Version: " | sed -e 's#^Plugin-Version: ##')
+ version=${version%%[[:space:]]}
+ echo $version
+}
+
# Copy files from /usr/share/jenkins/ref into $JENKINS_HOME
# So the initial JENKINS-HOME is set with expected content.
# Don't override, as this is just a reference setup, and use from UI
@@ -9,20 +22,94 @@
copy_reference_file() {
f="${1%/}"
b="${f%.override}"
- echo "$f" >> "$COPY_REFERENCE_FILE_LOG"
rel="${b:23}"
+ version_marker="${rel}.version_from_image"
dir=$(dirname "${b}")
- echo " $f -> $rel" >> "$COPY_REFERENCE_FILE_LOG"
- if [[ ! -e $JENKINS_HOME/${rel} || $f = *.override ]]
- then
- echo "copy $rel to JENKINS_HOME" >> "$COPY_REFERENCE_FILE_LOG"
- mkdir -p "$JENKINS_HOME/${dir:23}"
- cp -r "${f}" "$JENKINS_HOME/${rel}";
- # pin plugins on initial copy
- [[ ${rel} == plugins/*.jpi ]] && touch "$JENKINS_HOME/${rel}.pinned"
- fi;
+ local action;
+ local reason;
+ local container_version;
+ local image_version;
+ local marker_version;
+ local log; log=false
+ if [[ ${rel} == plugins/*.jpi ]]; then
+ container_version=$(get_plugin_version $JENKINS_HOME/${rel})
+ image_version=$(get_plugin_version ${f})
+ if [[ -e $JENKINS_HOME/${version_marker} ]]; then
+ marker_version=$(cat $JENKINS_HOME/${version_marker})
+ if versionLT $marker_version $container_version; then
+ action="SKIPPED"
+ reason="Installed version ($container_version) has been manually upgraded from initial version ($marker_version)"
+ log=true
+ else
+ if [[ "$image_version" == "$container_version" ]]; then
+ action="SKIPPED"
+ reason="Version from image is the same as the installed version $image_version"
+ else
+ if versionLT $image_version $container_version; then
+ action="SKIPPED"
+ log=true
+ reason="Image version ($image_version) is older than installed version ($container_version)"
+ else
+ action="UPGRADED"
+ log=true
+ reason="Image version ($image_version) is newer than installed version ($container_version)"
+ fi
+ fi
+ fi
+ else
+ if [[ -n "$TRY_UPGRADE_IF_NO_MARKER" ]]; then
+ if [[ "$image_version" == "$container_version" ]]; then
+ action="SKIPPED"
+ reason="Version from image is the same as the installed version $image_version (no marker found)"
+ # Add marker for next time
+ echo $image_version > $JENKINS_HOME/${version_marker}
+ else
+ if versionLT $image_version $container_version; then
+ action="SKIPPED"
+ log=true
+ reason="Image version ($image_version) is older than installed version ($container_version) (no marker found)"
+ else
+ action="UPGRADED"
+ log=true
+ reason="Image version ($image_version) is newer than installed version ($container_version) (no marker found)"
+ fi
+ fi
+ fi
+ fi
+ if [[ ! -e $JENKINS_HOME/${rel} || "$action" == "UPGRADED" || $f = *.override ]]; then
+ action=${action:-"INSTALLED"}
+ log=true
+ mkdir -p "$JENKINS_HOME/${dir:23}"
+ cp -r "${f}" "$JENKINS_HOME/${rel}";
+ # pin plugins on initial copy
+ touch "$JENKINS_HOME/${rel}.pinned"
+ echo $image_version > $JENKINS_HOME/${version_marker}
+ reason=${reason:-$image_version}
+ else
+ action=${action:-"SKIPPED"}
+ fi
+ else
+ if [[ ! -e $JENKINS_HOME/${rel} || $f = *.override ]]
+ then
+ action="INSTALLED"
+ log=true
+ mkdir -p "$JENKINS_HOME/${dir:23}"
+ cp -r "${f}" "$JENKINS_HOME/${rel}";
+ else
+ action="SKIPPED"
+ fi
+ fi
+ if [[ -n "$VERBOSE" || "$log" == "true" ]]; then
+ if [ -z "$reason" ]; then
+ echo "$action $rel" >> "$COPY_REFERENCE_FILE_LOG"
+ else
+ echo "$action $rel : $reason" >> "$COPY_REFERENCE_FILE_LOG"
+ fi
+ fi
}
: ${JENKINS_HOME:="/var/jenkins_home"}
+export -f versionLT
+export -f get_plugin_version
export -f copy_reference_file
touch "${COPY_REFERENCE_FILE_LOG}" || (echo "Can not write to ${COPY_REFERENCE_FILE_LOG}. Wrong volume permissions?" && exit 1)
echo "--- Copying files at $(date)" >> "$COPY_REFERENCE_FILE_LOG"
diff --git a/tests/test_helpers.bash b/tests/test_helpers.bash
index 63994f2..ed1462c 100644
--- a/tests/test_helpers.bash
+++ b/tests/test_helpers.bash
@@ -3,6 +3,7 @@
# check dependencies
(
type docker &>/dev/null || ( echo "docker is not available"; exit 1 )
+ type unzip &>/dev/null || ( echo "unzip is not available"; exit 1 )
type curl &>/dev/null || ( echo "curl is not available"; exit 1 )
)>&2
diff --git a/tests/tests.bats b/tests/tests.bats
index ce6d50d..ead87f1 100644
--- a/tests/tests.bats
+++ b/tests/tests.bats
@@ -78,3 +78,56 @@
@test "clean test containers" {
cleanup $SUT_CONTAINER
}
+
+@test "plugins are getting upgraded but not downgraded" {
+ run docker build -t $SUT_IMAGE-install-plugins $BATS_TEST_DIRNAME/install-plugins
+ assert_success
+ local work; work="$BATS_TEST_DIRNAME/upgrade-plugins/work"
+ # Image contains maven-plugin 2.7.1 and ant-plugin 1.3
+ run bash -c "docker run -ti -v $work:/var/jenkins_home --rm $SUT_IMAGE-install-plugins true"
+ assert_success
+ run bash -c "unzip -p $work/plugins/maven-plugin.jpi META-INF/MANIFEST.MF | tr -d '\r'"
+ assert_line 'Plugin-Version: 2.7.1'
+ run bash -c "unzip -p $work/plugins/ant.jpi META-INF/MANIFEST.MF | tr -d '\r'"
+ assert_line 'Plugin-Version: 1.3'
+ run docker build -t $SUT_IMAGE-upgrade-plugins $BATS_TEST_DIRNAME/upgrade-plugins
+ assert_success
+ # Images contains maven-plugin 2.13 and ant-plugin 1.2
+ run bash -c "docker run -ti -v $work:/var/jenkins_home --rm $SUT_IMAGE-upgrade-plugins true"
+ assert_success
+ run bash -c "unzip -p $work/plugins/maven-plugin.jpi META-INF/MANIFEST.MF | tr -d '\r'"
+ assert_success
+ # Should be updated
+ assert_line 'Plugin-Version: 2.13'
+ run bash -c "unzip -p $work/plugins/ant.jpi META-INF/MANIFEST.MF | tr -d '\r'"
+ # 1.2 is older than the existing 1.3, so keep 1.3
+ assert_line 'Plugin-Version: 1.3'
+}
+
+@test "clean work directory" {
+ run bash -c "rm -rf $BATS_TEST_DIRNAME/upgrade-plugins/work"
+}
+
+@test "do not upgrade if plugin has been manually updated" {
+ run docker build -t $SUT_IMAGE-install-plugins $BATS_TEST_DIRNAME/install-plugins
+ assert_success
+ local work; work="$BATS_TEST_DIRNAME/upgrade-plugins/work"
+ # Image contains maven-plugin 2.7.1 and ant-plugin 1.3
+ run bash -c "docker run -ti -v $work:/var/jenkins_home --rm $SUT_IMAGE-install-plugins curl --connect-timeout 5 --retry 5 --retry-delay 0 --retry-max-time 60 -s -f -L https://updates.jenkins.io/download/plugins/maven-plugin/2.12.1/maven-plugin.hpi -o /var/jenkins_home/plugins/maven-plugin.jpi"
+ assert_success
+ run bash -c "unzip -p $work/plugins/maven-plugin.jpi META-INF/MANIFEST.MF | tr -d '\r'"
+ assert_line 'Plugin-Version: 2.12.1'
+ run docker build -t $SUT_IMAGE-upgrade-plugins $BATS_TEST_DIRNAME/upgrade-plugins
+ assert_success
+ # Images contains maven-plugin 2.13 and ant-plugin 1.2
+ run bash -c "docker run -ti -v $work:/var/jenkins_home --rm $SUT_IMAGE-upgrade-plugins true"
+ assert_success
+ run bash -c "unzip -p $work/plugins/maven-plugin.jpi META-INF/MANIFEST.MF | tr -d '\r'"
+ assert_success
+ # Shouldn't be updated
+ refute_line 'Plugin-Version: 2.13'
+}
+
+@test "clean work directory" {
+ run bash -c "rm -rf $BATS_TEST_DIRNAME/upgrade-plugins/work"
+}
diff --git a/tests/upgrade-plugins/Dockerfile b/tests/upgrade-plugins/Dockerfile
new file mode 100644
index 0000000..dfe81de
--- /dev/null
+++ b/tests/upgrade-plugins/Dockerfile
@@ -0,0 +1,3 @@
+FROM bats-jenkins
+
+RUN /usr/local/bin/install-plugins.sh maven-plugin:2.13 ant:1.2