366 lines
9.6 KiB
Bash
Executable File
366 lines
9.6 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)"
|
|
|
|
profile=""
|
|
env_file="${repo_root}/.env.devprod"
|
|
compose_file=""
|
|
mode="auto"
|
|
occ_path=""
|
|
dry_run="0"
|
|
skip_finish="0"
|
|
bootstrap_now="0"
|
|
declare -a bootstrap_args=()
|
|
|
|
usage() {
|
|
cat <<USAGE
|
|
Usage: ./scripts/topology/apply-topology-profile.sh --profile <name> [options]
|
|
|
|
Apply an installation/repair profile selected by topology detection.
|
|
|
|
Profiles:
|
|
repo-devprod-bootstrap Uses repo Docker scripts (recreate + finish)
|
|
host-nextcloud-hybrid Host-Nextcloud adoption installer
|
|
|
|
Options:
|
|
--profile <name> Profile to apply (required)
|
|
--repo-root <path> Repository root (default: auto)
|
|
--env-file <path> Env file path (default: .env.devprod)
|
|
--compose-file <path> Compose file (auto-detected when omitted)
|
|
--mode auto|ssl|nossl Recreate mode (default: auto)
|
|
--occ-path <path> Host Nextcloud occ path (for host profile)
|
|
--dry-run Print commands without executing
|
|
--skip-finish Skip finish-initial-setup.sh after recreate
|
|
--bootstrap-now For host-nextcloud-hybrid, run install-host-nextcloud-hybrid.sh
|
|
--bootstrap-arg <arg> Extra argument passed through to the install script (repeatable)
|
|
-h, --help Show this help
|
|
USAGE
|
|
}
|
|
|
|
read_kv() {
|
|
local key="$1"
|
|
local file="$2"
|
|
local line
|
|
line="$(grep -m1 -E "^${key}=" "${file}" 2>/dev/null || true)"
|
|
if [[ -z "${line}" ]]; then
|
|
return 1
|
|
fi
|
|
printf '%s' "${line#*=}"
|
|
}
|
|
|
|
host_occ_cmd() {
|
|
if [[ -z "${occ_path:-}" || ! -f "${occ_path:-}" ]]; then
|
|
return 1
|
|
fi
|
|
if [[ -z "$(command -v php || true)" ]]; then
|
|
return 1
|
|
fi
|
|
if [[ "${EUID:-$(id -u)}" -eq 0 ]]; then
|
|
if command -v sudo >/dev/null 2>&1; then
|
|
sudo -u www-data php "${occ_path}" "$@"
|
|
return $?
|
|
fi
|
|
if command -v runuser >/dev/null 2>&1; then
|
|
runuser -u www-data -- php "${occ_path}" "$@"
|
|
return $?
|
|
fi
|
|
fi
|
|
php "${occ_path}" "$@"
|
|
}
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--profile)
|
|
profile="${2:-}"
|
|
shift 2
|
|
;;
|
|
--profile=*)
|
|
profile="${1#*=}"
|
|
shift
|
|
;;
|
|
--repo-root)
|
|
repo_root="${2:-}"
|
|
shift 2
|
|
;;
|
|
--repo-root=*)
|
|
repo_root="${1#*=}"
|
|
shift
|
|
;;
|
|
--env-file)
|
|
env_file="${2:-}"
|
|
shift 2
|
|
;;
|
|
--env-file=*)
|
|
env_file="${1#*=}"
|
|
shift
|
|
;;
|
|
--compose-file)
|
|
compose_file="${2:-}"
|
|
shift 2
|
|
;;
|
|
--compose-file=*)
|
|
compose_file="${1#*=}"
|
|
shift
|
|
;;
|
|
--mode)
|
|
mode="${2:-}"
|
|
shift 2
|
|
;;
|
|
--mode=*)
|
|
mode="${1#*=}"
|
|
shift
|
|
;;
|
|
--occ-path)
|
|
occ_path="${2:-}"
|
|
shift 2
|
|
;;
|
|
--occ-path=*)
|
|
occ_path="${1#*=}"
|
|
shift
|
|
;;
|
|
--dry-run)
|
|
dry_run="1"
|
|
shift
|
|
;;
|
|
--skip-finish)
|
|
skip_finish="1"
|
|
shift
|
|
;;
|
|
--bootstrap-now)
|
|
bootstrap_now="1"
|
|
shift
|
|
;;
|
|
--bootstrap-arg)
|
|
if [[ -z "${2:-}" ]]; then
|
|
echo "Missing value for --bootstrap-arg"
|
|
exit 1
|
|
fi
|
|
bootstrap_args+=("${2}")
|
|
shift 2
|
|
;;
|
|
--bootstrap-arg=*)
|
|
bootstrap_args+=("${1#*=}")
|
|
shift
|
|
;;
|
|
-h|--help)
|
|
usage
|
|
exit 0
|
|
;;
|
|
*)
|
|
echo "Unknown option: $1"
|
|
usage
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
if [[ -z "${profile}" ]]; then
|
|
echo "--profile is required."
|
|
usage
|
|
exit 1
|
|
fi
|
|
|
|
if [[ "${repo_root}" != /* ]]; then
|
|
repo_root="$(cd "${repo_root}" 2>/dev/null && pwd)"
|
|
fi
|
|
if [[ "${env_file}" != /* ]]; then
|
|
env_file="${repo_root}/${env_file}"
|
|
fi
|
|
if [[ -n "${compose_file}" && "${compose_file}" != /* ]]; then
|
|
compose_file="${repo_root}/${compose_file}"
|
|
fi
|
|
|
|
if [[ "${mode}" != "auto" && "${mode}" != "ssl" && "${mode}" != "nossl" ]]; then
|
|
echo "Invalid --mode value: ${mode}"
|
|
exit 1
|
|
fi
|
|
|
|
if [[ -z "${compose_file}" ]]; then
|
|
if [[ -f "${repo_root}/docker-compose.devprod.nossl.yml" ]]; then
|
|
compose_file="${repo_root}/docker-compose.devprod.nossl.yml"
|
|
elif [[ -f "${repo_root}/docker-compose.devprod.yml" ]]; then
|
|
compose_file="${repo_root}/docker-compose.devprod.yml"
|
|
else
|
|
compose_file="${repo_root}/docker-compose.devprod.nossl.yml"
|
|
fi
|
|
fi
|
|
|
|
run_cmd() {
|
|
if [[ "${dry_run}" == "1" ]]; then
|
|
printf '[dry-run] '
|
|
printf '%q ' "$@"
|
|
printf '\n'
|
|
return 0
|
|
fi
|
|
"$@"
|
|
}
|
|
|
|
detect_mode_from_compose_path() {
|
|
local input="${1:-}"
|
|
if [[ "${mode}" != "auto" ]]; then
|
|
printf '%s' "${mode}"
|
|
return 0
|
|
fi
|
|
if [[ "${input}" == *".nossl.yml" ]]; then
|
|
printf 'nossl'
|
|
else
|
|
printf 'ssl'
|
|
fi
|
|
}
|
|
|
|
apply_repo_devprod_bootstrap() {
|
|
if [[ ! -f "${env_file}" ]]; then
|
|
echo "Missing env file: ${env_file}"
|
|
exit 1
|
|
fi
|
|
if [[ ! -f "${compose_file}" ]]; then
|
|
echo "Missing compose file: ${compose_file}"
|
|
exit 1
|
|
fi
|
|
|
|
local effective_mode
|
|
effective_mode="$(detect_mode_from_compose_path "${compose_file}")"
|
|
|
|
local recreate_cmd=("${repo_root}/recreate-devprod.sh")
|
|
if [[ "${effective_mode}" == "nossl" ]]; then
|
|
recreate_cmd+=("--nossl")
|
|
else
|
|
recreate_cmd+=("--ssl")
|
|
fi
|
|
|
|
local external_auth_base_url
|
|
external_auth_base_url="$(read_kv "QORTAL_EXTERNAL_AUTH_BASE_URL" "${env_file}" || true)"
|
|
if [[ "${external_auth_base_url}" == *"external_auth"* ]]; then
|
|
recreate_cmd+=("--extauth")
|
|
fi
|
|
|
|
echo "Applying profile: repo-devprod-bootstrap"
|
|
echo "Repo root: ${repo_root}"
|
|
echo "Env file: ${env_file}"
|
|
echo "Compose file: ${compose_file}"
|
|
|
|
if [[ -x "${repo_root}/scripts/ensure-env-keys.sh" ]]; then
|
|
run_cmd "${repo_root}/scripts/ensure-env-keys.sh" --env-file "${env_file}" --template-file "${repo_root}/.env.example"
|
|
fi
|
|
|
|
run_cmd "${recreate_cmd[@]}"
|
|
|
|
if [[ "${skip_finish}" == "1" ]]; then
|
|
echo "Skipping finish-initial-setup by request (--skip-finish)."
|
|
return 0
|
|
fi
|
|
|
|
local finish_cmd=("${repo_root}/scripts/finish-initial-setup.sh")
|
|
if [[ "${effective_mode}" == "nossl" ]]; then
|
|
finish_cmd+=("--nossl")
|
|
else
|
|
finish_cmd+=("--ssl")
|
|
fi
|
|
finish_cmd+=("--env-file" "${env_file}")
|
|
run_cmd "${finish_cmd[@]}"
|
|
}
|
|
|
|
apply_host_nextcloud_hybrid() {
|
|
local nc_url=""
|
|
local dbtype=""
|
|
local docker_reachable="0"
|
|
local apps_list=""
|
|
local has_spreed="0"
|
|
local has_richdocuments="0"
|
|
local has_notify_push="0"
|
|
local install_script="${repo_root}/scripts/install-host-nextcloud-hybrid.sh"
|
|
|
|
echo "Applying profile: host-nextcloud-hybrid"
|
|
if [[ -z "${occ_path}" ]]; then
|
|
occ_path="/var/www/nextcloud/occ"
|
|
fi
|
|
echo "Detected/selected OCC path: ${occ_path}"
|
|
echo
|
|
|
|
if command -v docker >/dev/null 2>&1 && docker info >/dev/null 2>&1; then
|
|
docker_reachable="1"
|
|
fi
|
|
|
|
nc_url="$(host_occ_cmd config:system:get overwrite.cli.url 2>/dev/null | tr -d '\r' || true)"
|
|
dbtype="$(host_occ_cmd config:system:get dbtype 2>/dev/null | tr -d '\r' || true)"
|
|
apps_list="$(host_occ_cmd app:list 2>/dev/null || true)"
|
|
|
|
if grep -qE '^[[:space:]]+- spreed([[:space:]:]|$)' <<< "${apps_list}"; then
|
|
has_spreed="1"
|
|
fi
|
|
if grep -qE '^[[:space:]]+- richdocuments([[:space:]:]|$)' <<< "${apps_list}"; then
|
|
has_richdocuments="1"
|
|
fi
|
|
if grep -qE '^[[:space:]]+- notify_push([[:space:]:]|$)' <<< "${apps_list}"; then
|
|
has_notify_push="1"
|
|
fi
|
|
|
|
echo "Observed host state:"
|
|
echo " nextcloud_url: ${nc_url:-<unknown>}"
|
|
echo " dbtype: ${dbtype:-<unknown>}"
|
|
echo " docker_daemon_reachable: ${docker_reachable}"
|
|
echo " spreed_enabled: ${has_spreed}"
|
|
echo " richdocuments_enabled: ${has_richdocuments}"
|
|
echo " notify_push_enabled: ${has_notify_push}"
|
|
echo
|
|
echo "Recommended adoption path for this topology:"
|
|
echo "1) Keep host Nextcloud, Apache, DB, and Redis in place."
|
|
if [[ "${has_spreed}" == "1" || "${has_richdocuments}" == "1" || "${has_notify_push}" == "1" ]]; then
|
|
echo "2) Reuse existing host-integrated Nextcloud apps and sidecars where present:"
|
|
[[ "${has_notify_push}" == "1" ]] && echo " - notify_push already enabled"
|
|
[[ "${has_richdocuments}" == "1" ]] && echo " - richdocuments already enabled"
|
|
[[ "${has_spreed}" == "1" ]] && echo " - spreed already enabled"
|
|
echo " Prefer adding NuQloud auth/broker pieces around them before replacing any Talk/Office setup."
|
|
else
|
|
echo "2) No existing Talk/Office app enablement detected; this host may be a cleaner candidate for fuller NuQloud sidecar adoption."
|
|
fi
|
|
echo "3) Provision Docker sidecars for the missing NuQloud services:"
|
|
echo " - broker"
|
|
echo " - broker_db"
|
|
echo " - external_auth"
|
|
echo " - optional qortal_node"
|
|
echo "4) Apply the host-hybrid installer:"
|
|
echo " ./scripts/install-host-nextcloud-hybrid.sh --occ-path ${occ_path}"
|
|
echo "5) Use the lifecycle helpers for later operations:"
|
|
echo " ./scripts/update-host-nextcloud-hybrid.sh"
|
|
echo " ./scripts/restart-host-nextcloud-hybrid.sh"
|
|
echo " ./scripts/stop-host-nextcloud-hybrid.sh"
|
|
echo "6) Re-run topology detection after changes:"
|
|
echo " ./scripts/topology/discover-cloud-topology.sh --text --repo-root ${repo_root}"
|
|
|
|
if [[ "${bootstrap_now}" != "1" ]]; then
|
|
return 0
|
|
fi
|
|
|
|
if [[ ! -x "${install_script}" ]]; then
|
|
echo
|
|
echo "Cannot run install: missing executable ${install_script}"
|
|
exit 1
|
|
fi
|
|
|
|
echo
|
|
echo "Running host installer now (--bootstrap-now)..."
|
|
local bootstrap_cmd=("${install_script}" "--repo-root" "${repo_root}" "--occ-path" "${occ_path}")
|
|
if [[ "${#bootstrap_args[@]}" -gt 0 ]]; then
|
|
bootstrap_cmd+=("${bootstrap_args[@]}")
|
|
fi
|
|
|
|
run_cmd "${bootstrap_cmd[@]}"
|
|
}
|
|
|
|
case "${profile}" in
|
|
repo-devprod-bootstrap)
|
|
apply_repo_devprod_bootstrap
|
|
;;
|
|
host-nextcloud-hybrid)
|
|
apply_host_nextcloud_hybrid
|
|
;;
|
|
*)
|
|
echo "Unknown profile: ${profile}"
|
|
usage
|
|
exit 1
|
|
;;
|
|
esac
|