#!/bin/bash # Nextcloud upgrade verifier. # --------------------------------------------------------------------------- # Nextcloud is the reason stepped upgrades exist here: it refuses to cross more # than one major ("Updates between multiple major versions and downgrades are # unsupported") and simply will not start. So the ladder must be certain each # major finished before starting the next. # # `occ status` is the authoritative answer and reports exactly the three facts # that matter — whether the instance is installed, whether it is still in # maintenance mode, and whether a database upgrade is outstanding — plus the # version actually running. Container health tells you none of that: during the # post-upgrade migration the container is up and healthy while the instance is # in maintenance mode with the schema half-converted. # # Runs through the app's own occ wrapper idiom (docker exec -u www-data), so it # inherits whatever the rest of the Nextcloud tooling already relies on. # nextcloud_upgrade_verify # 0 only when the instance is installed, out of maintenance, has no pending DB # upgrade, and reports the major version the tag asked for. nextcloud_upgrade_verify() { local app="$1" expected="$2" deadline="$3" # "34-fpm-alpine" -> 34. The tag's leading number IS the major; occ reports # a full version (34.0.2.1) and only the major is comparable. local want_major; want_major="$(printf '%s' "$expected" | grep -oE '^[0-9]+')" local last="" while [ "$(date +%s)" -lt "$deadline" ]; do local out out="$(runFileOp docker exec -u www-data nextcloud-service php occ status --output=json 2>/dev/null | tr -d '\r')" if [ -n "$out" ] && printf '%s' "$out" | grep -q '"installed"'; then local installed maint needs_db ver major if command -v jq >/dev/null 2>&1; then installed="$(printf '%s' "$out" | jq -r '.installed // false' 2>/dev/null)" maint="$(printf '%s' "$out" | jq -r '.maintenance // false' 2>/dev/null)" needs_db="$(printf '%s' "$out" | jq -r '.needsDbUpgrade // false' 2>/dev/null)" ver="$(printf '%s' "$out" | jq -r '.versionstring // ""' 2>/dev/null)" else installed="$(printf '%s' "$out" | grep -o '"installed":[^,}]*' | cut -d: -f2 | tr -d ' "')" maint="$(printf '%s' "$out" | grep -o '"maintenance":[^,}]*' | cut -d: -f2 | tr -d ' "')" needs_db="$(printf '%s' "$out" | grep -o '"needsDbUpgrade":[^,}]*' | cut -d: -f2 | tr -d ' "')" ver="$(printf '%s' "$out" | grep -o '"versionstring":"[^"]*"' | cut -d'"' -f4)" fi major="$(printf '%s' "$ver" | cut -d. -f1)" last="installed=$installed maintenance=$maint needsDbUpgrade=$needs_db version=$ver" if [ "$installed" = "true" ] && [ "$maint" = "false" ] && [ "$needs_db" = "false" ] \ && [ -n "$want_major" ] && [ "$major" = "$want_major" ]; then isSuccessful "Nextcloud reports $ver, out of maintenance, no pending DB upgrade." return 0 fi # Maintenance mode mid-migration is EXPECTED and not a failure — # keep waiting. Only the deadline ends this. isNotice "Nextcloud not ready yet: $last" fi sleep 10 done isError "Nextcloud did not reach a verified state for $expected before the deadline.${last:+ Last status: $last}" return 1 }