From a7e1078a824d4642bbf10ee04efe3480f90dd512 Mon Sep 17 00:00:00 2001 From: Valentin Lab Date: Wed, 31 Aug 2022 19:18:15 +0200 Subject: [PATCH] new: [nextcloud] add ``upgrade`` action. Signed-off-by: Valentin Lab --- nextcloud/actions/upgrade | 270 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 270 insertions(+) create mode 100755 nextcloud/actions/upgrade diff --git a/nextcloud/actions/upgrade b/nextcloud/actions/upgrade new file mode 100755 index 0000000..8d8902d --- /dev/null +++ b/nextcloud/actions/upgrade @@ -0,0 +1,270 @@ +#!/bin/bash +## compose: no-hooks + + +if [ -z "$SERVICE_DATASTORE" ]; then + echo "This script is meant to be run through 'compose' to work properly." >&2 + exit 1 +fi + +version=0.1 +usage="$exname [-h|--help] [--force|-f] [TARGET_VERSION]" +help=" +USAGE: + +$usage + +DESCRIPTION: + +Migrate the current nextcloud service to given target version. Don't +forget to change your =compose.yml= accordingly afterwards. + +EXAMPLES: + + $exname 21.0.0 + +" + +no_hint= +force= +target= +while [ "$1" ]; do + case "$1" in + "--help"|"-h") + print_help >&2 + exit 0 + ;; + "--force"|"-f") + force=yes + ;; + "--no-hint") + no_hint=yes + ;; + --*|-*) + err "Unexpected optional argument '$1'" + print_usage >&2 + exit 1 + ;; + *) + [ -z "$target" ] && { target=$1 ; shift ; continue ; } + err "Unexpected positional argument '$1'" + print_usage >&2 + exit 1 + ;; + esac + shift +done + +nextcloud:config:version() { + cat "$SERVICE_CONFIGSTORE/var/www/html/config/config.php" | + grep "'version' =>" | + cut -f 4 -d \' | + cut -f 1-3 -d . +} + +nextcloud:code:version() { + cat "$SERVICE_DATASTORE/var/www/html/version.php" | + grep 'VersionString =' | + cut -f 3 -d ' ' | + cut -f 2 -d \' +} + +current_image_version="${DOCKER_BASE_IMAGE#*:}" +current_image_version="${current_image_version%-myc}" + + +if ! [[ "$current_image_version" =~ ^[0-9]+.[0-9]+.[0-9]+$ ]]; then + err "Current nextcloud version '$current_image_version' is unsupported yet." + exit 1 +fi + + +if ! [ -e "$SERVICE_DATASTORE/var/www/html/version.php" ]; then + err "No code seem to have been deployed yet in datastore." \ + "This is not supported yet." + exit 1 +fi + +current_code_version=$(nextcloud:code:version) + +if [ "$current_code_version" != "$current_image_version" ]; then + err "Current code version ${WHITE}$current_code_version${NORMAL}" \ + "mismatch with current image version" \ + "${WHITE}$current_image_version${NORMAL}" + exit 1 +fi + +current_config_version=$(nextcloud:config:version) + +info "Current config version: ${WHITE}$current_config_version${NORMAL}" +if [ "$current_config_version" != "$current_code_version" ]; then + warn "Current config version ${WHITE}$current_config_version${NORMAL}" \ + "mismatch with current code version" \ + "${WHITE}$current_code_version${NORMAL}" + echo " Will use the config version as reference for upgrade." >&2 +fi + +last_available_versions=( + $(DEBUG= docker:tags:fetch docker.0k.io/nextcloud 30 '[0-9]+\.[0-9+]\.[0-9]+-myc$' | + sed -r 's/-myc$//g' | + sort -rV) +) + +## XXXvlab: put this in kal-shlib-common +version_gt() { test "$(printf '%s\n' "$@" | sort -V | head -n 1)" != "$1"; } + +last_upgradable_versions=() +for v in "${last_available_versions[@]}"; do + if version_gt "$v" "$current_config_version"; then + last_upgradable_versions+=("$v") + fi +done + +if [ "${#last_upgradable_versions[@]}" == 0 ]; then + info "${DARKYELLOW}nextcloud${NORMAL} is already ${GREEN}up-to-date${NORMAL}." + exit 0 +fi + +if [ -z "$target" ]; then + info "Target latest version: ${WHITE}${last_available_versions[0]}${NORMAL}" + target=${last_upgradable_versions[0]} +else + if [[ "* $target *" != " ${last_available_versions[*]} " ]]; then + err "Invalid version $target selected, please specify one of:" + for v in "${last_upgradable_versions[@]}"; do + echo " - $v" + done >&2 + exit 1 + fi + info "Target version ${WHITE}$target${NORMAL}" +fi + + +upgrade_path=($(echo "${last_upgradable_versions[*]}" | tr ' ' '\n' | uniq -w 3 | sort -V)) + +containers="$(get_running_containers_for_service "$SERVICE_NAME")" + +container_stopped=() +if [ -n "$containers" ]; then + #err "Running container(s) for $DARKYELLOW$SERVICE_NAME$NORMAL are still running:" + for container in $containers; do + docker stop "$container" >/dev/null || { + err "Failed to stop container '$container'." + exit 1 + } + container_stopped+=("$container") + done +fi + +## XXXvlab: taking first container is probably not a good idea +container="$(echo "$containers" | head -n 1)" + +settmpdir MIGRATION_TMPDIR +set -o pipefail +for image_version in "${upgrade_path[@]}"; do + + while true; do + patched=() + + current_code_version=$(nextcloud:code:version) + current_config_version=$(nextcloud:config:version) + if [ "$current_config_version" == "$image_version" ]; then + err "Unexpected step where config version ${WHITE}$current_config_version${NORMAL} is same than image version" + exit 1 + fi + if ! version_gt "$image_version" "$current_config_version"; then + err "Unexpected step where config version ${WHITE}$current_config_version${NORMAL} is greater than image version ${WHITE}$image_version${NORMAL}" + exit 1 + fi + if (( ${image_version%%.*} - ${current_config_version%%.*} > 1 )); then + err "Unexpected step where config version ${WHITE}$current_config_version${NORMAL} is more than one major version less than image version ${WHITE}$image_version${NORMAL}" + exit 1 + fi + if [ "$current_code_version" == "$image_version" ]; then + ## Code already setup, we need to call ``occ upgrade`` by our selves + info "Upgrading ${WHITE}$current_config_version${NORMAL} => ${WHITE}$image_version${NORMAL} (db)" + compose --no-hooks \ + --add-compose-content="$SERVICE_NAME: + docker-compose: + image: docker.0k.io/nextcloud:${image_version}-myc" \ + run --rm \ + -u www-data --entrypoint /var/www/html/occ "$SERVICE_NAME" \ + upgrade 2>&1 | + tee "$MIGRATION_TMPDIR/migration.log" + errlvl="$?" + else + ## Code will be upgraded + info "Upgrading ${WHITE}$current_config_version${NORMAL} => ${WHITE}$image_version${NORMAL} (code, db)" + compose --no-hooks \ + --add-compose-content="$SERVICE_NAME: + docker-compose: + image: docker.0k.io/nextcloud:${image_version}-myc" \ + run --rm \ + -v "$CHARM_PATH"/src/fake-apache:/usr/bin/apache \ + --entrypoint /entrypoint.sh "$SERVICE_NAME" apache 2>&1 | + tee "$MIGRATION_TMPDIR/migration.log" + errlvl="$?" + fi + + [ "$errlvl" == 0 ] && continue 2 + + ## + ## Damage control, there are some things we can solve + ## + if grep "^Update failed" "$MIGRATION_TMPDIR/migration.log" >/dev/null 2>&1; then + + ## XXXvlab: this comes from and should move to onlyoffice charm in + ## some way. + if grep "Update app onlyoffice" "$MIGRATION_TMPDIR/migration.log" >/dev/null 2>&1 && + grep "SQLSTATE" "$MIGRATION_TMPDIR/migration.log" >/dev/null 2>&1; then + + if [ -e "$DATASTORE"/"$SERVICE_NAME/var/www/html/custom_apps/onlyoffice/lib/Migration/Version070400Date20220607111111.php" ]; then + patch="$CHARM_PATH/../onlyoffice/src/patch/00-onlyoffice-nextcloud.patch" + if ! [[ " ${patched[*]} " == *" $patch "* ]]; then + if ( + cd "$DATASTORE"/"$SERVICE_NAME/var/www/html/custom_apps/onlyoffice/"; + patch -Np1 --dry-run < "$patch" ); then + info "Found OnlyOffice issue, correcting it, and retrying." + ( + cd "$DATASTORE"/"$SERVICE_NAME/var/www/html/custom_apps/onlyoffice/"; + patch -Np1 < "$patch" + ) || exit 1 + patched+=("$patch") + continue + fi + fi + fi + fi + fi + err "Upgrade to ${WHITE}$image_version${NORMAL} ${DARKRED}failed${NORMAL}. Aborting." + exit 1 + + done +done +if grep "^Nextcloud is in maintenance mode" "$MIGRATION_TMPDIR/migration.log" >/dev/null 2>&1; then + info "Forcing maintenance mode off" + compose --no-hooks \ + --add-compose-content="$SERVICE_NAME: + docker-compose: + image: docker.0k.io/nextcloud:${target}-myc" \ + run --rm \ + -u www-data --entrypoint /var/www/html/occ "$SERVICE_NAME" \ + maintenance:mode --off +fi +info "Successfully upgraded from ${WHITE}$current_config_version${NORMAL} to ${WHITE}$target${NORMAL}" + +if [ -z "no_hint" ]; then + cat <&2 +Don't forget to force the version in your \`\`compose.yml\`\`. For instance: + + ${DARKYELLOW}$SERVICE_NAME${NORMAL}: + + ${DARKGRAY}# ...${NORMAL} + + ${WHITE}docker-compose${NORMAL}: + ${WHITE}image${NORMAL}: docker.0k.io/nextcloud:${target}-myc + + ${DARKGRAY}# ...${NORMAL} + +EOF +fi \ No newline at end of file