292 lines
7.1 KiB
Bash
Executable File
292 lines
7.1 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
repo_root="$(cd "${script_dir}/.." && pwd)"
|
|
source "${script_dir}/lib-compose-project.sh"
|
|
|
|
compose_file=""
|
|
env_file=""
|
|
app_service="app"
|
|
verify_only="0"
|
|
|
|
usage() {
|
|
cat <<'USAGE'
|
|
Usage: ./scripts/ensure-nextcloud-office-config.sh --compose-file <file> --env-file <file> [options]
|
|
|
|
Ensures Nextcloud Office / Collabora configuration matches env values.
|
|
|
|
Options:
|
|
--compose-file <path> Docker compose file to use (required)
|
|
--env-file <path> Env file to use (required)
|
|
--app-service <name> Nextcloud app service name (default: app)
|
|
--verify-only Do not attempt repairs; only verify current state
|
|
-h, --help Show this help
|
|
USAGE
|
|
}
|
|
|
|
read_kv() {
|
|
local key="$1"
|
|
local line
|
|
line="$(grep -m1 -E "^${key}=" "${env_file}" || true)"
|
|
if [[ -z "${line}" ]]; then
|
|
return 1
|
|
fi
|
|
echo "${line#*=}"
|
|
}
|
|
|
|
trim_csv() {
|
|
local raw="${1:-}"
|
|
local cleaned
|
|
cleaned="$(echo "${raw}" | tr -d '[:space:]')"
|
|
cleaned="${cleaned#,}"
|
|
cleaned="${cleaned%,}"
|
|
echo "${cleaned}"
|
|
}
|
|
|
|
profile_enabled() {
|
|
local profiles="$1"
|
|
local name="$2"
|
|
[[ ",${profiles}," == *",${name},"* ]]
|
|
}
|
|
|
|
compute_public_url() {
|
|
local domain="$1"
|
|
local https_port="$2"
|
|
if [[ -z "${domain}" ]]; then
|
|
echo ""
|
|
return 0
|
|
fi
|
|
if [[ -n "${https_port}" && "${https_port}" != "443" ]]; then
|
|
echo "https://${domain}:${https_port}"
|
|
else
|
|
echo "https://${domain}"
|
|
fi
|
|
}
|
|
|
|
ensure_docker_access() {
|
|
local docker_path=""
|
|
docker_path="$(type -P docker || true)"
|
|
if [[ -z "${docker_path}" ]]; then
|
|
echo "docker is required"
|
|
exit 1
|
|
fi
|
|
|
|
if "${docker_path}" info >/dev/null 2>&1; then
|
|
DOCKER_CMD=("${docker_path}")
|
|
return 0
|
|
fi
|
|
|
|
if ! command -v sudo >/dev/null 2>&1; then
|
|
echo "docker is installed but this user cannot access it, and sudo is unavailable."
|
|
exit 1
|
|
fi
|
|
|
|
if sudo -n "${docker_path}" info >/dev/null 2>&1; then
|
|
DOCKER_CMD=(sudo "${docker_path}")
|
|
return 0
|
|
fi
|
|
|
|
echo "docker requires elevated privileges on this machine."
|
|
echo "You may be prompted for your sudo password."
|
|
if sudo "${docker_path}" info >/dev/null 2>&1; then
|
|
DOCKER_CMD=(sudo "${docker_path}")
|
|
return 0
|
|
fi
|
|
|
|
echo "Unable to access docker, even with sudo."
|
|
exit 1
|
|
}
|
|
|
|
docker() {
|
|
"${DOCKER_CMD[@]}" "$@"
|
|
}
|
|
|
|
compose_cmd() {
|
|
docker compose -f "${compose_file}" --env-file "${env_file}" "$@"
|
|
}
|
|
|
|
occ_exec() {
|
|
compose_cmd exec -T --user www-data "${app_service}" php occ "$@"
|
|
}
|
|
|
|
occ_exec_quiet_retry() {
|
|
local rc=1
|
|
local max_attempts="${OCC_RETRY_ATTEMPTS:-6}"
|
|
local retry_sleep="${OCC_RETRY_SLEEP_SECONDS:-4}"
|
|
local attempt
|
|
if [[ $# -eq 0 ]]; then
|
|
return 1
|
|
fi
|
|
for attempt in $(seq 1 "${max_attempts}"); do
|
|
occ_exec "$@" >/dev/null 2>&1
|
|
rc=$?
|
|
if [[ "${rc}" -eq 0 ]]; then
|
|
return 0
|
|
fi
|
|
sleep "${retry_sleep}"
|
|
done
|
|
return "${rc}"
|
|
}
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--compose-file)
|
|
compose_file="${2:-}"
|
|
shift 2
|
|
;;
|
|
--compose-file=*)
|
|
compose_file="${1#*=}"
|
|
shift
|
|
;;
|
|
--env-file)
|
|
env_file="${2:-}"
|
|
shift 2
|
|
;;
|
|
--env-file=*)
|
|
env_file="${1#*=}"
|
|
shift
|
|
;;
|
|
--app-service)
|
|
app_service="${2:-}"
|
|
shift 2
|
|
;;
|
|
--app-service=*)
|
|
app_service="${1#*=}"
|
|
shift
|
|
;;
|
|
--verify-only)
|
|
verify_only="1"
|
|
shift
|
|
;;
|
|
-h|--help)
|
|
usage
|
|
exit 0
|
|
;;
|
|
*)
|
|
echo "Unknown option: $1"
|
|
usage
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
if [[ -z "${compose_file}" || -z "${env_file}" ]]; then
|
|
usage
|
|
exit 1
|
|
fi
|
|
|
|
if [[ "${compose_file}" != /* ]]; then
|
|
compose_file="${repo_root}/${compose_file}"
|
|
fi
|
|
if [[ "${env_file}" != /* ]]; then
|
|
env_file="${repo_root}/${env_file}"
|
|
fi
|
|
|
|
if [[ ! -f "${compose_file}" ]]; then
|
|
echo "Missing compose file: ${compose_file}"
|
|
exit 1
|
|
fi
|
|
if [[ ! -f "${env_file}" ]]; then
|
|
echo "Missing env file: ${env_file}"
|
|
exit 1
|
|
fi
|
|
|
|
export_compose_project_name_from_env "${env_file}" || true
|
|
ensure_docker_access
|
|
|
|
profiles="$(trim_csv "$(read_kv "COMPOSE_PROFILES" || true)")"
|
|
if ! profile_enabled "${profiles}" "office"; then
|
|
echo "Office profile not enabled in ${env_file}; nothing to do."
|
|
exit 0
|
|
fi
|
|
|
|
if ! occ_exec status >/dev/null 2>&1; then
|
|
echo "Nextcloud OCC is not ready in service '${app_service}'."
|
|
exit 1
|
|
fi
|
|
|
|
collabora_public_url="$(read_kv "COLLABORA_PUBLIC_URL" || true)"
|
|
collabora_public_url="${collabora_public_url%/}"
|
|
if [[ -z "${collabora_public_url}" ]]; then
|
|
collabora_domain="$(read_kv "COLLABORA_DOMAIN" || true)"
|
|
public_https_port="$(read_kv "PUBLIC_HTTPS_PORT" || true)"
|
|
if [[ -z "${public_https_port}" ]]; then
|
|
public_https_port="$(read_kv "CADDY_HTTPS_PORT" || true)"
|
|
fi
|
|
collabora_public_url="$(compute_public_url "${collabora_domain}" "${public_https_port}")"
|
|
fi
|
|
|
|
if [[ -z "${collabora_public_url}" ]]; then
|
|
echo "Missing COLLABORA_PUBLIC_URL or COLLABORA_DOMAIN while office profile is enabled."
|
|
exit 1
|
|
fi
|
|
|
|
status=0
|
|
office_enable_status=0
|
|
office_wopi_status=0
|
|
office_public_wopi_status=0
|
|
|
|
echo "Ensuring Nextcloud Office configuration..."
|
|
echo " compose_file=${compose_file}"
|
|
echo " env_file=${env_file}"
|
|
echo " collabora_public_url=${collabora_public_url}"
|
|
|
|
if [[ "${verify_only}" != "1" ]]; then
|
|
if occ_exec_quiet_retry app:enable --force richdocuments; then
|
|
office_enable_status=0
|
|
else
|
|
office_enable_status=1
|
|
occ_exec_quiet_retry app:install richdocuments >/dev/null 2>&1 || true
|
|
if occ_exec_quiet_retry app:enable --force richdocuments; then
|
|
office_enable_status=0
|
|
else
|
|
office_enable_status=1
|
|
fi
|
|
fi
|
|
|
|
if occ_exec_quiet_retry config:app:set richdocuments wopi_url --value="${collabora_public_url}"; then
|
|
office_wopi_status=0
|
|
else
|
|
office_wopi_status=1
|
|
fi
|
|
if occ_exec_quiet_retry config:app:set richdocuments public_wopi_url --value="${collabora_public_url}"; then
|
|
office_public_wopi_status=0
|
|
else
|
|
office_public_wopi_status=1
|
|
fi
|
|
fi
|
|
|
|
if [[ "${office_enable_status}" -ne 0 || "${office_wopi_status}" -ne 0 || "${office_public_wopi_status}" -ne 0 ]]; then
|
|
status=1
|
|
fi
|
|
|
|
if ! occ_exec app:list --enabled 2>/dev/null | grep -qE '^[[:space:]]+- richdocuments:'; then
|
|
echo "richdocuments app is not enabled."
|
|
status=1
|
|
fi
|
|
|
|
current_wopi_url="$(occ_exec config:app:get richdocuments wopi_url 2>/dev/null | tr -d '\r' || true)"
|
|
current_public_wopi_url="$(occ_exec config:app:get richdocuments public_wopi_url 2>/dev/null | tr -d '\r' || true)"
|
|
if [[ "${current_wopi_url%/}" != "${collabora_public_url}" ]]; then
|
|
echo "richdocuments wopi_url mismatch: ${current_wopi_url:-<empty>}"
|
|
status=1
|
|
fi
|
|
if [[ "${current_public_wopi_url%/}" != "${collabora_public_url}" ]]; then
|
|
echo "richdocuments public_wopi_url mismatch: ${current_public_wopi_url:-<empty>}"
|
|
status=1
|
|
fi
|
|
|
|
echo "Office verification summary:"
|
|
echo " richdocuments_enabled=$([[ "${status}" -eq 0 ]] && echo yes || echo check_failed)"
|
|
echo " wopi_url=${current_wopi_url:-<empty>}"
|
|
echo " public_wopi_url=${current_public_wopi_url:-<empty>}"
|
|
|
|
if [[ "${status}" -eq 0 ]]; then
|
|
echo "Office configuration verified."
|
|
else
|
|
echo "Office configuration verification failed."
|
|
fi
|
|
|
|
exit "${status}"
|