From: Pablo Zmdl Date: Thu, 2 Oct 2025 16:38:10 +0000 (+0200) Subject: Pre-setup and post-setup tasks X-Git-Url: http://git.99rst.org/?a=commitdiff_plain;h=1d8ea95d37f10903197f7d98b0b038e8805e285f;p=roundcube-roundcubemail-docker.git Pre-setup and post-setup tasks All executable files present in /entrypoint-tasks/pre-setup/ and /entrypoint-tasks/post-setup/ are run at the beginning or at the end, respectively, of the actual entrypoint-script. Each of the executed files receive the CMD given to the container as their arguments. This allows e.g. to change a plugin's config, or install a technical requirement of a plugin that is to be installed. This feature is not implemented in the images for Roundcube v1.5, since they are not well maintained and will be dropped soon, anyways. --- diff --git a/.github/workflows/test-1.5.yml b/.github/workflows/test-1.5.yml index 4385893..de56497 100644 --- a/.github/workflows/test-1.5.yml +++ b/.github/workflows/test-1.5.yml @@ -53,6 +53,7 @@ jobs: # Set these here so the values are visible in the logs for debugging. export ROUNDCUBEMAIL_TEST_IMAGE="${{ matrix.docker-tag }}" export HTTP_PORT="${{ matrix.http-port || '80' }}" + export SKIP_POST_SETUP_SCRIPT_TEST="yes" for testFile in ${{ join(matrix.test-files, ' ') }}; do docker compose -f ./tests/docker-compose.test-${testFile}.yml \ diff --git a/README.md b/README.md index dbdb3ff..ae1fadf 100644 --- a/README.md +++ b/README.md @@ -149,6 +149,19 @@ For example: ROUNDCUBEMAIL_PLUGINS: thunderbird_labels, show_folder_size, tls_icon ``` +To overwrite the default config of a plugin you might need to use a post-setup script (see below) that moves a custom config file into the plugin's directory. + +## Pre-setup and post-setup tasks + +In order to execute custom tasks before or after Roundcubemail is set up in the container, you can bind-mount directories to `/entrypoint-tasks/pre-setup/` and `/entrypoint-tasks/post-setup/`. Then all executable files in those directories are executed at the beginning or the end of the actual entrypoint-script, respectively. If an executable exits with a code > 1, the entrypoint script exits, too. + +Each executable receives the container's `CMD` as arguments. + +They are executed in alphabetical order (the way `bash` understands it in `en_US` locale). + +If the Roundcubemail-setup is skipped due to a custom `CMD`, these tasks are skipped as well. + + ## HTTPS Currently all images are configured to speak HTTP. To provide HTTPS please run an additional reverse proxy in front of them, which handles certificates and terminates TLS. Alternatively you could derive from our images (or use the advanced configuration methods) to make Apache or nginx provide HTTPS – but please refrain from opening issues asking for support with such a setup. diff --git a/apache/docker-entrypoint.sh b/apache/docker-entrypoint.sh index cb2fc38..600d0f0 100755 --- a/apache/docker-entrypoint.sh +++ b/apache/docker-entrypoint.sh @@ -3,7 +3,36 @@ # PWD=`pwd` +run_entrypoint_tasks() { + phase="$1" + shift + shopt -s nullglob + echo "Running $phase-setup tasks:" + for file in /entrypoint-tasks/"$phase-setup"/*; do + if test ! -f "$file"; then + echo "Ignoring $file because it is not a regular file." + continue; + fi + if test ! -x "$file"; then + echo "Ignoring $file because it is not executable." + continue; + fi + echo "Running $phase-setup task $file:" + "$file" "$@" + # Exit in case of an error in an executable. + exit_code=$? + if test $exit_code -ne 0; then + echo "The task exited with code $exit_code, thus the entrypoint script is exiting, too!" + exit $exit_code + fi + echo 'Done.' + done + shopt -u nullglob +} + if [[ "$1" == apache2* || "$1" == php-fpm || "$1" == bin* ]]; then + run_entrypoint_tasks pre "$@" + INSTALLDIR=`pwd` # docroot is empty if ! [ -e index.php -a -e bin/installto.sh ]; then @@ -207,6 +236,7 @@ if [[ "$1" == apache2* || "$1" == php-fpm || "$1" == bin* ]]; then which apk && apk add --no-cache $ASPELL_PACKAGES fi + run_entrypoint_tasks post "$@" fi exec "$@" diff --git a/fpm-alpine/docker-entrypoint.sh b/fpm-alpine/docker-entrypoint.sh index cb2fc38..600d0f0 100755 --- a/fpm-alpine/docker-entrypoint.sh +++ b/fpm-alpine/docker-entrypoint.sh @@ -3,7 +3,36 @@ # PWD=`pwd` +run_entrypoint_tasks() { + phase="$1" + shift + shopt -s nullglob + echo "Running $phase-setup tasks:" + for file in /entrypoint-tasks/"$phase-setup"/*; do + if test ! -f "$file"; then + echo "Ignoring $file because it is not a regular file." + continue; + fi + if test ! -x "$file"; then + echo "Ignoring $file because it is not executable." + continue; + fi + echo "Running $phase-setup task $file:" + "$file" "$@" + # Exit in case of an error in an executable. + exit_code=$? + if test $exit_code -ne 0; then + echo "The task exited with code $exit_code, thus the entrypoint script is exiting, too!" + exit $exit_code + fi + echo 'Done.' + done + shopt -u nullglob +} + if [[ "$1" == apache2* || "$1" == php-fpm || "$1" == bin* ]]; then + run_entrypoint_tasks pre "$@" + INSTALLDIR=`pwd` # docroot is empty if ! [ -e index.php -a -e bin/installto.sh ]; then @@ -207,6 +236,7 @@ if [[ "$1" == apache2* || "$1" == php-fpm || "$1" == bin* ]]; then which apk && apk add --no-cache $ASPELL_PACKAGES fi + run_entrypoint_tasks post "$@" fi exec "$@" diff --git a/fpm/docker-entrypoint.sh b/fpm/docker-entrypoint.sh index cb2fc38..600d0f0 100755 --- a/fpm/docker-entrypoint.sh +++ b/fpm/docker-entrypoint.sh @@ -3,7 +3,36 @@ # PWD=`pwd` +run_entrypoint_tasks() { + phase="$1" + shift + shopt -s nullglob + echo "Running $phase-setup tasks:" + for file in /entrypoint-tasks/"$phase-setup"/*; do + if test ! -f "$file"; then + echo "Ignoring $file because it is not a regular file." + continue; + fi + if test ! -x "$file"; then + echo "Ignoring $file because it is not executable." + continue; + fi + echo "Running $phase-setup task $file:" + "$file" "$@" + # Exit in case of an error in an executable. + exit_code=$? + if test $exit_code -ne 0; then + echo "The task exited with code $exit_code, thus the entrypoint script is exiting, too!" + exit $exit_code + fi + echo 'Done.' + done + shopt -u nullglob +} + if [[ "$1" == apache2* || "$1" == php-fpm || "$1" == bin* ]]; then + run_entrypoint_tasks pre "$@" + INSTALLDIR=`pwd` # docroot is empty if ! [ -e index.php -a -e bin/installto.sh ]; then @@ -207,6 +236,7 @@ if [[ "$1" == apache2* || "$1" == php-fpm || "$1" == bin* ]]; then which apk && apk add --no-cache $ASPELL_PACKAGES fi + run_entrypoint_tasks post "$@" fi exec "$@" diff --git a/templates/docker-entrypoint.sh b/templates/docker-entrypoint.sh index cb2fc38..600d0f0 100644 --- a/templates/docker-entrypoint.sh +++ b/templates/docker-entrypoint.sh @@ -3,7 +3,36 @@ # PWD=`pwd` +run_entrypoint_tasks() { + phase="$1" + shift + shopt -s nullglob + echo "Running $phase-setup tasks:" + for file in /entrypoint-tasks/"$phase-setup"/*; do + if test ! -f "$file"; then + echo "Ignoring $file because it is not a regular file." + continue; + fi + if test ! -x "$file"; then + echo "Ignoring $file because it is not executable." + continue; + fi + echo "Running $phase-setup task $file:" + "$file" "$@" + # Exit in case of an error in an executable. + exit_code=$? + if test $exit_code -ne 0; then + echo "The task exited with code $exit_code, thus the entrypoint script is exiting, too!" + exit $exit_code + fi + echo 'Done.' + done + shopt -u nullglob +} + if [[ "$1" == apache2* || "$1" == php-fpm || "$1" == bin* ]]; then + run_entrypoint_tasks pre "$@" + INSTALLDIR=`pwd` # docroot is empty if ! [ -e index.php -a -e bin/installto.sh ]; then @@ -207,6 +236,7 @@ if [[ "$1" == apache2* || "$1" == php-fpm || "$1" == bin* ]]; then which apk && apk add --no-cache $ASPELL_PACKAGES fi + run_entrypoint_tasks post "$@" fi exec "$@" diff --git a/tests/docker-compose.test-apache-postgres.yml b/tests/docker-compose.test-apache-postgres.yml index 0967a0a..f3d9626 100644 --- a/tests/docker-compose.test-apache-postgres.yml +++ b/tests/docker-compose.test-apache-postgres.yml @@ -26,6 +26,9 @@ services: - ROUNDCUBEMAIL_DB_USER=roundcube # same as pgsql POSTGRES_USER env name - ROUNDCUBEMAIL_DB_PASSWORD=roundcube # same as pgsql POSTGRES_PASSWORD env name - ROUNDCUBEMAIL_SKIN=larry # Install non-default skin + volumes: + - "./pre-setup/:/entrypoint-tasks/pre-setup/" + - "./post-setup/:/entrypoint-tasks/post-setup/" roundcubedb: image: postgres:alpine @@ -59,6 +62,7 @@ services: command: /tests/run.sh environment: - ROUNDCUBE_URL=http://roundcubemail:${HTTP_PORT:-80}/ + - SKIP_POST_SETUP_SCRIPT_TEST=${SKIP_POST_SETUP_SCRIPT_TEST:-no} volumes: - ./run.sh:/tests/run.sh:ro working_dir: /tests diff --git a/tests/docker-compose.test-fpm-postgres.yml b/tests/docker-compose.test-fpm-postgres.yml index b2a8cf6..3a32b1a 100644 --- a/tests/docker-compose.test-fpm-postgres.yml +++ b/tests/docker-compose.test-fpm-postgres.yml @@ -21,6 +21,8 @@ services: - roundcubemail-fpm volumes: - www-vol:/var/www/html + - "./pre-setup/:/entrypoint-tasks/pre-setup/" + - "./post-setup/:/entrypoint-tasks/post-setup/" environment: - ROUNDCUBEMAIL_DB_TYPE=pgsql - ROUNDCUBEMAIL_DB_HOST=roundcubedb # same as pgsql container name @@ -89,6 +91,7 @@ services: working_dir: /tests environment: ROUNDCUBE_URL: http://roundcubenginx/ + SKIP_POST_SETUP_SCRIPT_TEST: ${SKIP_POST_SETUP_SCRIPT_TEST:-no} networks: roundcube_test_net: diff --git a/tests/post-setup/script.sh b/tests/post-setup/script.sh new file mode 100755 index 0000000..62a2440 --- /dev/null +++ b/tests/post-setup/script.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +set -e + +# Check that the file, which a pre-setup-script should have created, is present. +test -f /tmp/something + +# Leave a marker that can be checked from the outside. +echo yes > public_html/post_setup_script.txt diff --git a/tests/pre-setup/a-script b/tests/pre-setup/a-script new file mode 100755 index 0000000..86f8b95 --- /dev/null +++ b/tests/pre-setup/a-script @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +set -e + +touch /tmp/something +touch /tmp/anotherfile diff --git a/tests/pre-setup/b-not b/tests/pre-setup/b-not new file mode 100644 index 0000000..e982dfd --- /dev/null +++ b/tests/pre-setup/b-not @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +set -e + +# This script should not be run by the entrypoint-script! +# +# Create a regular file, so we can check that it doesn't exist in a later running script. +touch /tmp/shouldnotexist diff --git a/tests/pre-setup/c-check b/tests/pre-setup/c-check new file mode 100755 index 0000000..ebbf79e --- /dev/null +++ b/tests/pre-setup/c-check @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +set -e + +# Remove a file we previously created in "a-script.sh". If this fails, there's a problem in the order of script +# execution. +rm /tmp/anotherfile + +if test -f /tmp/shouldnotexist; then + echo "Error: File /tmp/shouldnotexist should not exist but does!" + exit 1 +fi diff --git a/tests/run.sh b/tests/run.sh index 79678d4..51e5703 100755 --- a/tests/run.sh +++ b/tests/run.sh @@ -31,4 +31,11 @@ findText 'Login' "${HOMEPAGE_TEXT}" findText 'Warning: This webmail service requires Javascript!' "${HOMEPAGE_TEXT}" echo 'Homepage is okay' -echo 'End.' \ No newline at end of file +if test "$SKIP_POST_SETUP_SCRIPT_TEST" != "yes"; then + echo 'Checking post-setup-script marker' + POST_SETUP_SCRIPT_TEXT=$(curl -s --fail "${ROUNDCUBE_URL}post_setup_script.txt") + findText 'yes' "${POST_SETUP_SCRIPT_TEXT}" + echo 'post-setup-script marker is ok' +fi + +echo 'End.'