Checks version skip, pending DB upgrade, occ update:check status, and non-shipped app compatibility (with an apps.nextcloud.com fallback lookup) to verify if it looks safe to upgrade to the next Nextcloud major version.
353 lines
13 KiB
Bash
353 lines
13 KiB
Bash
#!/bin/bash
|
|
|
|
export FPM_TUNE_VERSION=v5
|
|
export NGINX_CONF_VERSION=v8
|
|
export MY_CNF_VERSION=v6
|
|
export ENTRYPOINT_VERSION=v3
|
|
export ENTRYPOINT_WHITEBOARD_VERSION=v1
|
|
export ENTRYPOINT_TALK_VERSION=v1
|
|
export CRONTAB_VERSION=v1
|
|
export PG_BACKUP_VERSION=v2
|
|
|
|
run_occ() {
|
|
# NOTE: uses $* (not $@) so this still works when called with multiple args as seperate words.
|
|
su -p www-data -s /bin/sh -c "/var/www/html/occ $*"
|
|
}
|
|
|
|
install_apps() {
|
|
install_apps="$@"
|
|
if [ -z "$install_apps" ]; then
|
|
install_apps=$APPS
|
|
fi
|
|
for app in $install_apps; do
|
|
run_occ "app:install $app"
|
|
done
|
|
}
|
|
|
|
set_app_config() {
|
|
APP=$1
|
|
KEY=$2
|
|
VALUE=$3
|
|
run_occ "config:app:set $APP $KEY --value '$VALUE'"
|
|
}
|
|
|
|
set_system_config() {
|
|
KEY=$1
|
|
VALUE=$2
|
|
run_occ "config:system:set $KEY --value '$VALUE'"
|
|
}
|
|
|
|
set_trusted_proxies() {
|
|
trusted_proxies="$@"
|
|
if [ -z "$1" ]; then
|
|
trusted_proxies="$TRUSTED_PROXIES"
|
|
fi
|
|
set_system_config trusted_proxies "$trusted_proxies"
|
|
}
|
|
|
|
set_logfile_stdout() {
|
|
set_system_config logfile '/dev/stdout'
|
|
}
|
|
|
|
customize() {
|
|
if [ -z "$1" ]
|
|
then
|
|
echo "Usage: ... customize <assets_path>"
|
|
exit 1
|
|
fi
|
|
asset_dir=$1
|
|
for asset in $COPY_ASSETS; do
|
|
source=$(echo $asset | cut -d "|" -f1)
|
|
target=$(echo $asset | cut -d "|" -f2)
|
|
echo copy $source to $target
|
|
abra app cp $APP_NAME $asset_dir/$source $target
|
|
done
|
|
|
|
abra app cmd -T $APP_NAME app set_app_config theming color \"$THEMING_COLOR\"
|
|
abra app cmd -T $APP_NAME app set_app_config theming slogan \"$THEMING_SLOGAN\"
|
|
abra app cmd -T $APP_NAME app run_occ '"theming:config background \"/var/www/html/themes/flow_background.jpg\""'
|
|
abra app cmd -T $APP_NAME app run_occ '"theming:config logo \"/var/www/html/themes/icon_left_brand.svg\""'
|
|
abra app cmd -T $APP_NAME app run_occ '"theming:config logoheader \"/var/www/html/themes/icon.png\""'
|
|
}
|
|
|
|
install_bbb() {
|
|
install_apps bbb
|
|
set_app_config bbb app.navigation true
|
|
set_app_config bbb api.url "$BBB_URL"
|
|
set_app_config bbb api.secret "$(cat /run/secrets/bbb_secret)"
|
|
}
|
|
|
|
install_onlyoffice() {
|
|
install_apps onlyoffice
|
|
set_app_config onlyoffice DocumentServerUrl "$ONLYOFFICE_URL"
|
|
set_app_config onlyoffice jwt_secret "$(cat /run/secrets/onlyoffice_jwt)"
|
|
set_app_config onlyoffice customizationForcesave true
|
|
}
|
|
|
|
install_collabora() {
|
|
install_apps richdocuments
|
|
set_app_config richdocuments wopi_url "$COLLABORA_URL"
|
|
# important for security reaosns
|
|
# https://docs.nextcloud.com/server/latest/admin_manual/office/configuration.html#wopi-settings
|
|
set_app_config richdocuments wopi_allowlist "$COLLABORA_ALLOWLIST"
|
|
}
|
|
|
|
install_whiteboard() {
|
|
install_apps whiteboard
|
|
set_app_config whiteboard collabBackendUrl "https://${DOMAIN}/whiteboard"
|
|
set_app_config whiteboard jwt_secret_key "$(cat /run/secrets/whiteboard_jwt)"
|
|
}
|
|
|
|
|
|
install_talk() {
|
|
install_apps spreed
|
|
run_occ "talk:signaling:add --verify 'wss://${TALK_DOMAIN}' '$(cat /run/secrets/talk_signaling_secret)'"
|
|
run_occ "talk:stun:add '${TALK_DOMAIN}:3478'"
|
|
run_occ "talk:stun:add '${TALK_DOMAIN}:443'"
|
|
run_occ "talk:turn:add --secret='$(cat /run/secrets/talk_turn_secret)' turn '${TALK_DOMAIN}:3478' udp,tcp"
|
|
|
|
}
|
|
|
|
install_fulltextsearch() {
|
|
install_apps fulltextsearch
|
|
install_apps fulltextsearch_elasticsearch
|
|
install_apps files_fulltextsearch
|
|
set_app_config fulltextsearch search_platform "OCA\\FullTextSearch_Elasticsearch\\Platform\\ElasticSearchPlatform"
|
|
set_app_config fulltextsearch_elasticsearch elastic_host "http://elastic:$(cat /run/secrets/elasticsearch_password)@elasticsearch:9200/"
|
|
set_app_config fulltextsearch_elasticsearch elastic_index "nextcloud"
|
|
set_app_config files_fulltextsearch files_local "1"
|
|
}
|
|
|
|
set_default_quota() {
|
|
set_app_config files default_quota "$DEFAULT_QUOTA"
|
|
}
|
|
|
|
set_authentik() {
|
|
install_apps sociallogin
|
|
AUTHENTIK_SECRET=$(cat /run/secrets/authentik_secret)
|
|
AUTHENTIK_ID=$(cat /run/secrets/authentik_id)
|
|
set_system_config logo_url https://$AUTHENTIK_DOMAIN
|
|
set_app_config sociallogin custom_providers "
|
|
{
|
|
\"custom_oidc\":[
|
|
{
|
|
\"name\":\"$AUTHENTIK_USER_PREFIX\",
|
|
\"title\":\"authentik\",
|
|
\"authorizeUrl\": \"https://$AUTHENTIK_DOMAIN/application/o/authorize/\",
|
|
\"tokenUrl\": \"https://$AUTHENTIK_DOMAIN/application/o/token/\",
|
|
\"displayNameClaim\":\"preferred_username\",
|
|
\"userInfoUrl\": \"https://$AUTHENTIK_DOMAIN/application/o/userinfo/\",
|
|
\"logoutUrl\": \"https://$AUTHENTIK_DOMAIN/application/o/nextcloud/end-session/\",
|
|
\"clientId\":\"$AUTHENTIK_ID\",
|
|
\"clientSecret\":\"$AUTHENTIK_SECRET\",
|
|
\"scope\":\"openid profile email nextcloud\",
|
|
\"groupsClaim\":\"nextcloud_groups\",
|
|
\"style\":\"openid\",
|
|
\"defaultGroup\":\"\",
|
|
\"groupMapping\": {
|
|
\"admin\": \"admin\",
|
|
\"authentik Admins\": \"admin\"
|
|
}
|
|
}
|
|
]
|
|
}"
|
|
|
|
set_app_config sociallogin update_profile_on_login 1
|
|
set_app_config sociallogin auto_create_groups 1
|
|
set_app_config sociallogin hide_default_login 1
|
|
run_occ 'config:system:set social_login_auto_redirect --value true'
|
|
run_occ 'config:system:set allow_user_to_change_display_name --value=false'
|
|
run_occ 'config:system:set lost_password_link --value=disabled'
|
|
}
|
|
|
|
set_user_oidc() {
|
|
install_apps user_oidc
|
|
USER_OIDC_SECRET=$(cat /run/secrets/user_oidc_secret)
|
|
run_occ "user_oidc:provider \
|
|
--clientid=${USER_OIDC_ID} \
|
|
--clientsecret=${USER_OIDC_SECRET} \
|
|
--discoveryuri=${USER_OIDC_DISCOVERY_URI} \
|
|
--endsessionendpointuri=${USER_OIDC_END_SESSION_URI} \
|
|
--postlogouturi=https://${DOMAIN} \
|
|
--scope='openid email profile' \
|
|
${USER_OIDC_PROVIDER}"
|
|
# disable non user_oidc login
|
|
if [[ ${USER_OIDC_LOGIN_ONLY:-false} = "true" ]]; then
|
|
run_occ "config:app:set --value=0 user_oidc allow_multiple_user_backends"
|
|
fi
|
|
}
|
|
|
|
disable_skeletondirectory() {
|
|
run_occ "config:system:set skeletondirectory --value ''"
|
|
}
|
|
|
|
set_windowsfriendly_filenames() {
|
|
run_occ 'config:system:set forbidden_filename_characters 0 --value=?'
|
|
run_occ 'config:system:set forbidden_filename_characters 1 --value=\<'
|
|
run_occ 'config:system:set forbidden_filename_characters 2 --value=\>'
|
|
run_occ 'config:system:set forbidden_filename_characters 3 --value=:'
|
|
run_occ 'config:system:set forbidden_filename_characters 4 --value=*'
|
|
run_occ 'config:system:set forbidden_filename_characters 5 --value=\|'
|
|
run_occ 'config:system:set forbidden_filename_characters 6 --value=\"'
|
|
}
|
|
|
|
upgrade_mariadb() {
|
|
mariadb-upgrade -p`cat /run/secrets/db_root_password`
|
|
}
|
|
|
|
# Checks whether this instance looks ready to update to the next Nextcloud
|
|
# major version.
|
|
#
|
|
# Usage:
|
|
# abra app cmd <app-name> app check_major_upgrade
|
|
# abra app cmd <app-name> app check_major_upgrade 33 # check readiness for a specific target
|
|
#
|
|
# What it checks:
|
|
# - current version is exactly one major behind the target
|
|
# - no pending DB upgrade from a previous, unfinished update
|
|
# - whether a newer release is available on the current major
|
|
# (recommended before upgradeing to the next major)
|
|
# - every enabled, non-shipped app's compatibility with the target major
|
|
# - for apps that don't, whether apps.nextcloud.com already has a newer
|
|
# release that does
|
|
#
|
|
# It does NOT check every precondition, always read the release notes
|
|
# from Nextcloud too.
|
|
check_major_upgrade() {
|
|
target_major=$1
|
|
|
|
echo "=== Nextcloud major upgrade readiness check ==="
|
|
|
|
status_json=$(run_occ status --output=json 2>/dev/null)
|
|
if [ -z "$status_json" ]; then
|
|
echo "[FAIL] Could not read 'occ status' - is Nextcloud installed and reachable?"
|
|
return 1
|
|
fi
|
|
|
|
current_version=$(echo "$status_json" | php -r '$d=json_decode(stream_get_contents(STDIN),true); echo $d["versionstring"] ?? "";')
|
|
current_major=${current_version%%.*}
|
|
needs_db_upgrade=$(echo "$status_json" | php -r '$d=json_decode(stream_get_contents(STDIN),true); echo ($d["needsDbUpgrade"] ?? false) ? "true" : "false";')
|
|
|
|
if [ -z "$current_major" ]; then
|
|
echo "[FAIL] Could not determine the current Nextcloud version from 'occ status'."
|
|
return 1
|
|
fi
|
|
|
|
if [ -z "$target_major" ]; then
|
|
target_major=$((current_major + 1))
|
|
fi
|
|
|
|
echo "Current version: $current_version"
|
|
echo "Target major version: $target_major"
|
|
|
|
ok=true
|
|
|
|
if [ "$target_major" -le "$current_major" ]; then
|
|
echo "[FAIL] Target major ($target_major) is not newer than the current major ($current_major)."
|
|
ok=false
|
|
elif [ "$target_major" -gt "$((current_major + 1))" ]; then
|
|
echo "[FAIL] Cannot skip major versions. Upgrade to $((current_major + 1)) first."
|
|
ok=false
|
|
fi
|
|
|
|
if [ "$needs_db_upgrade" = "true" ]; then
|
|
echo "[FAIL] A pending database upgrade was detected. Run 'occ upgrade' for the current version first."
|
|
ok=false
|
|
fi
|
|
|
|
echo
|
|
echo "--- occ update:check ---"
|
|
update_check_output=$(run_occ "update:check" 2>&1)
|
|
if [ -z "$update_check_output" ]; then
|
|
echo "[WARN] 'occ update:check' produced no output, could not verify."
|
|
elif echo "$update_check_output" | grep -q "Everything up to date"; then
|
|
echo "[OK] Everything up to date."
|
|
else
|
|
available_version=$(echo "$update_check_output" | grep -oE 'Nextcloud [0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?' | head -n1 | awk '{print $2}')
|
|
available_major=${available_version%%.*}
|
|
if [ -z "$available_major" ]; then
|
|
echo "[WARN] Could not parse 'occ update:check' output to determine the available version."
|
|
elif [ "$available_major" = "$current_major" ]; then
|
|
echo "[WARN] $available_version is available on the current major. Recommended to update to that before upgrading to $target_major."
|
|
else
|
|
echo "[OK] Already on the latest release of major $current_major (next available update is $available_version)."
|
|
fi
|
|
fi
|
|
echo
|
|
|
|
echo "--- Non-shipped app compatibility with Nextcloud $target_major ---"
|
|
echo "(shipped apps are skipped, they come bundled with the docker image)"
|
|
apps_json=$(run_occ "app:list --shipped=false --enabled --output=json" 2>/dev/null)
|
|
|
|
if [ -z "$apps_json" ]; then
|
|
echo "[WARN] 'occ app:list' returned no output, could not check non-shipped app compatibility."
|
|
enabled_apps=""
|
|
else
|
|
apps_json_valid=$(echo "$apps_json" | php -r '$d=json_decode(stream_get_contents(STDIN),true); echo (json_last_error() === JSON_ERROR_NONE && is_array($d)) ? "1" : "0";')
|
|
if [ "$apps_json_valid" != "1" ]; then
|
|
echo "[WARN] Could not parse 'occ app:list' output, could not check non-shipped app compatibility."
|
|
enabled_apps=""
|
|
else
|
|
enabled_apps=$(echo "$apps_json" | php -r '$d=json_decode(stream_get_contents(STDIN),true); foreach(array_keys($d["enabled"] ?? []) as $a) echo $a."\n";')
|
|
if [ -z "$enabled_apps" ]; then
|
|
echo "No non-shipped apps are enabled - nothing to check here."
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
compatible_apps=""
|
|
compatible_apps_fetched=0
|
|
|
|
for app in $enabled_apps; do
|
|
info_file=$(find /var/www/html/apps /var/www/html/custom_apps -maxdepth 3 -type f -ipath "*/$app/appinfo/info.xml" 2>/dev/null | head -n1)
|
|
|
|
if [ -z "$info_file" ]; then
|
|
echo "[WARN] $app: could not locate appinfo/info.xml, skipping"
|
|
continue
|
|
fi
|
|
|
|
max_version=$(php -r '
|
|
$x = @simplexml_load_file($argv[1]);
|
|
$dep = $x ? ($x->dependencies->nextcloud ?? null) : null;
|
|
echo $dep !== null ? (string)$dep["max-version"] : "";
|
|
' "$info_file")
|
|
|
|
if [ -z "$max_version" ]; then
|
|
echo "[WARN] $app: no max-version declared in info.xml, assume compatible but verify manually"
|
|
continue
|
|
fi
|
|
|
|
if [ "${max_version%%.*}" -ge "$target_major" ] 2>/dev/null; then
|
|
echo "[OK] $app: installed version supports up to Nextcloud $max_version"
|
|
continue
|
|
fi
|
|
|
|
echo "[INFO] $app: installed version only supports up to Nextcloud $max_version"
|
|
|
|
if [ "$compatible_apps_fetched" != "1" ]; then
|
|
compatible_apps_fetched=1
|
|
compatible_apps=$(curl -fsSL --max-time 30 "https://apps.nextcloud.com/api/v1/platform/${target_major}.0.0/apps.json" 2>/dev/null \
|
|
| php -r '$d=json_decode(stream_get_contents(STDIN),true); if(is_array($d)) foreach($d as $a) echo $a["id"]."\n";')
|
|
fi
|
|
|
|
if [ -z "$compatible_apps" ]; then
|
|
echo "[FAIL] $app: could not reach apps.nextcloud.com to check for a newer compatible release, verify manually"
|
|
ok=false
|
|
elif echo "$compatible_apps" | grep -qxF "$app"; then
|
|
echo "[WARN] $app: apps.nextcloud.com has a release that supports $target_major. It may not update until Nextcloud is upgraded, occ upgrade will try to update it automatically"
|
|
else
|
|
echo "[FAIL] $app: no apps.nextcloud.com release supports $target_major yet, it will be disabled during the upgrade"
|
|
ok=false
|
|
fi
|
|
done
|
|
|
|
echo
|
|
if [ "$ok" = true ]; then
|
|
echo "=== READY: no blocking issues found for upgrade to major $target_major ==="
|
|
return 0
|
|
else
|
|
echo "=== NOT READY: resolve the [FAIL] items above before running the upgrade ==="
|
|
return 1
|
|
fi
|
|
}
|