forked from 0k/0k-charms
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
303 lines
10 KiB
303 lines
10 KiB
#!/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() {
|
|
for f in {"$SERVICE_CONFIGSTORE","$SERVICE_DATASTORE"}/var/www/html/config/config.php; do
|
|
if [ -e "$f" ]; then
|
|
cat "$f"
|
|
break
|
|
fi
|
|
done |
|
|
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
|
|
|
|
docker_version=$(docker info --format '{{.ServerVersion}}')
|
|
last_compatible_versions=()
|
|
for v in "${last_upgradable_versions[@]}"; do
|
|
if version_gt "$docker_version" 20.10.0; then
|
|
last_compatible_versions+=("$v")
|
|
continue
|
|
fi
|
|
if version_gt "26.99.99" "$v"; then
|
|
last_compatible_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 [[ " ${last_available_versions[*]} " != *" $target "* ]]; then
|
|
err "Invalid version ${WHITE}$target${NORMAL} 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
|
|
|
|
if [[ " ${last_compatible_versions[*]} " != *" $target "* ]]; then
|
|
err "Sorry, ${DARKYELLOW}$SERVICE_NAME${NORMAL} ${WHITE}$target${NORMAL}" \
|
|
"require docker version >= ${WHITE}20.10${NORMAL} (current: $docker_version)"
|
|
echo " Nextcloud versions <= ${WHITE}27${NORMAL} are still supported." >&2
|
|
echo " You can specify one of:" >&2
|
|
for v in "${last_compatible_versions[@]}"; do
|
|
echo " - $v" >&2
|
|
done
|
|
exit 1
|
|
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
|
|
}
|
|
docker rm "$container" > /dev/null || {
|
|
err "Couldn't delete container '$container'."
|
|
}
|
|
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
|
|
docker rmi "docker.0k.io/nextcloud:${current_config_version}-myc" >/dev/null 2>&1 || true
|
|
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 ||
|
|
grep "^Database error when running migration latest for app onlyoffice" "$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 <<EOF >&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
|