396 lines
11 KiB
Bash
Executable File
396 lines
11 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)"
|
|
|
|
action=""
|
|
env_file=".env.devprod"
|
|
compose_file=""
|
|
mode="auto"
|
|
topology="auto"
|
|
broker_dir="/opt/qortal-broker"
|
|
broker_dir_explicit="0"
|
|
env_file_explicit="0"
|
|
compose_file_explicit="0"
|
|
dry_run="0"
|
|
force_refresh_contexts="0"
|
|
finish_host_nextcloud_upgrade="0"
|
|
rebuild_qortal="0"
|
|
full_rebuild="0"
|
|
extauth="auto"
|
|
qortal_branch=""
|
|
qortal_branch_next="0"
|
|
|
|
usage() {
|
|
cat <<USAGE
|
|
Usage: ./scripts/nuqloud-lifecycle.sh <action> [options]
|
|
|
|
Smart lifecycle wrapper for NuQloud installs. Detects repo Docker devprod vs
|
|
host Nextcloud hybrid installs and delegates to the existing lifecycle scripts.
|
|
|
|
Actions:
|
|
detect Print detected topology
|
|
start Start/recreate services for the detected topology
|
|
update Refresh code/config and recreate managed services
|
|
rebuild Rebuild containers where supported, then recreate services
|
|
stop Stop managed services without deleting volumes
|
|
|
|
Options:
|
|
--env-file <path> Repo devprod env or host broker env hint
|
|
--compose-file <path> Compose file hint for detection/host start/stop
|
|
--mode auto|ssl|nossl Repo devprod mode (default: auto)
|
|
--topology auto|repo-devprod|host-hybrid
|
|
Override topology detection
|
|
--broker-dir <path> Host-hybrid broker dir (default: /opt/qortal-broker)
|
|
--extauth|--no-extauth Repo devprod external-auth profile hint
|
|
--qortal Include/rebuild qortal_node where supported
|
|
--qortal-branch <branch> Rebuild Qortal Core from a specific branch
|
|
--full Full repo devprod rebuild where supported
|
|
--force-refresh-contexts Allow dirty git context refreshes in host update
|
|
--finish-host-nextcloud-upgrade Permit host Nextcloud occ upgrade repair flow
|
|
--dry-run Print the delegated command only
|
|
-h, --help Show this help
|
|
USAGE
|
|
}
|
|
|
|
resolve_path() {
|
|
local raw="${1:-}"
|
|
if [[ -z "${raw}" ]]; then
|
|
printf '%s' ""
|
|
elif [[ "${raw}" == /* ]]; then
|
|
printf '%s' "${raw}"
|
|
else
|
|
printf '%s' "${repo_root}/${raw}"
|
|
fi
|
|
}
|
|
|
|
print_cmd() {
|
|
printf 'Would run:'
|
|
printf ' %q' "$@"
|
|
printf '\n'
|
|
}
|
|
|
|
run_or_print() {
|
|
if [[ "${dry_run}" == "1" ]]; then
|
|
print_cmd "$@"
|
|
return 0
|
|
fi
|
|
"$@"
|
|
}
|
|
|
|
json_string_value() {
|
|
local key="$1"
|
|
sed -nE "s/.*\"${key}\"[[:space:]]*:[[:space:]]*\"([^\"]*)\".*/\\1/p" | head -n1
|
|
}
|
|
|
|
infer_mode_from_compose() {
|
|
local file="${1:-}"
|
|
if [[ "${mode}" != "auto" ]]; then
|
|
printf '%s' "${mode}"
|
|
elif [[ "${file}" == *".nossl."* || "${file}" == *"nossl"* ]]; then
|
|
printf '%s' "nossl"
|
|
else
|
|
printf '%s' "ssl"
|
|
fi
|
|
}
|
|
|
|
detect_topology_json() {
|
|
local args=(--repo-root "${repo_root}" --env-file "${resolved_env_file}" --json)
|
|
if [[ -n "${resolved_compose_file}" ]]; then
|
|
args+=(--compose-file "${resolved_compose_file}")
|
|
fi
|
|
"${script_dir}/discover-cloud-topology.sh" "${args[@]}"
|
|
}
|
|
|
|
detect_topology_id() {
|
|
local json id
|
|
json="$(detect_topology_json 2>/dev/null || true)"
|
|
id="$(printf '%s\n' "${json}" | json_string_value "id")"
|
|
|
|
if [[ -z "${id}" && -f "${resolved_broker_dir}/.env" && -f "${resolved_broker_dir}/docker-compose.yml" ]]; then
|
|
id="host_nextcloud_plus_docker"
|
|
fi
|
|
if [[ -z "${id}" && -f "${resolved_env_file}" ]]; then
|
|
id="docker_compose_generic"
|
|
fi
|
|
|
|
printf '%s' "${id:-unknown}"
|
|
}
|
|
|
|
repo_devprod_cmd() {
|
|
local delegated_mode="$1"
|
|
local cmd=()
|
|
|
|
case "${action}" in
|
|
start)
|
|
cmd=("${repo_root}/start-devprod.sh" "--${delegated_mode}")
|
|
if [[ "${extauth}" == "1" ]]; then
|
|
cmd+=(--extauth)
|
|
elif [[ "${extauth}" == "0" ]]; then
|
|
cmd+=(--no-extauth)
|
|
fi
|
|
;;
|
|
update|rebuild)
|
|
cmd=("${repo_root}/recreate-devprod.sh" "--${delegated_mode}")
|
|
[[ "${extauth}" == "1" ]] && cmd+=(--extauth)
|
|
[[ "${rebuild_qortal}" == "1" ]] && cmd+=(--qortal)
|
|
[[ "${full_rebuild}" == "1" ]] && cmd+=(--full)
|
|
[[ -n "${qortal_branch}" ]] && cmd+=(--qortal-branch "${qortal_branch}")
|
|
;;
|
|
stop)
|
|
cmd=("${repo_root}/stop-devprod.sh" "--mode" "${delegated_mode}")
|
|
;;
|
|
*)
|
|
echo "Unsupported repo devprod action: ${action}" >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
run_or_print "${cmd[@]}"
|
|
}
|
|
|
|
host_hybrid_cmd() {
|
|
local host_env_file="${resolved_broker_dir}/.env"
|
|
local host_compose_file="${resolved_broker_dir}/docker-compose.yml"
|
|
local cmd=()
|
|
|
|
if [[ -n "${compose_file}" ]]; then
|
|
host_compose_file="${resolved_compose_file}"
|
|
fi
|
|
if [[ "${env_file}" != ".env.devprod" || -f "${resolved_env_file}" && "${resolved_env_file}" == "${resolved_broker_dir}/.env" ]]; then
|
|
host_env_file="${resolved_env_file}"
|
|
fi
|
|
|
|
case "${action}" in
|
|
start)
|
|
cmd=("${script_dir}/restart-host-nextcloud-hybrid.sh" --broker-dir "${resolved_broker_dir}" --env-file "${host_env_file}" --compose-file "${host_compose_file}")
|
|
[[ "${rebuild_qortal}" == "1" ]] && cmd+=(--qortal)
|
|
;;
|
|
update|rebuild)
|
|
cmd=("${script_dir}/update-host-nextcloud-hybrid.sh" --broker-dir "${resolved_broker_dir}")
|
|
[[ "${force_refresh_contexts}" == "1" ]] && cmd+=(--force-refresh-contexts)
|
|
[[ "${finish_host_nextcloud_upgrade}" == "1" ]] && cmd+=(--finish-host-nextcloud-upgrade)
|
|
;;
|
|
stop)
|
|
cmd=("${script_dir}/stop-host-nextcloud-hybrid.sh" --broker-dir "${resolved_broker_dir}" --env-file "${host_env_file}" --compose-file "${host_compose_file}")
|
|
;;
|
|
*)
|
|
echo "Unsupported host-hybrid action: ${action}" >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
run_or_print "${cmd[@]}"
|
|
}
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
if [[ "${qortal_branch_next}" == "1" ]]; then
|
|
qortal_branch="${1:-}"
|
|
qortal_branch_next="0"
|
|
shift
|
|
continue
|
|
fi
|
|
|
|
case "$1" in
|
|
detect|start|update|rebuild|stop)
|
|
action="$1"
|
|
shift
|
|
;;
|
|
--env-file)
|
|
env_file="${2:-}"
|
|
env_file_explicit="1"
|
|
shift 2
|
|
;;
|
|
--env-file=*)
|
|
env_file="${1#*=}"
|
|
env_file_explicit="1"
|
|
shift
|
|
;;
|
|
--compose-file)
|
|
compose_file="${2:-}"
|
|
compose_file_explicit="1"
|
|
shift 2
|
|
;;
|
|
--compose-file=*)
|
|
compose_file="${1#*=}"
|
|
compose_file_explicit="1"
|
|
shift
|
|
;;
|
|
--mode)
|
|
mode="${2:-}"
|
|
shift 2
|
|
;;
|
|
--mode=*)
|
|
mode="${1#*=}"
|
|
shift
|
|
;;
|
|
--topology)
|
|
topology="${2:-}"
|
|
shift 2
|
|
;;
|
|
--topology=*)
|
|
topology="${1#*=}"
|
|
shift
|
|
;;
|
|
--ssl)
|
|
mode="ssl"
|
|
shift
|
|
;;
|
|
--nossl)
|
|
mode="nossl"
|
|
shift
|
|
;;
|
|
--broker-dir)
|
|
broker_dir="${2:-}"
|
|
broker_dir_explicit="1"
|
|
shift 2
|
|
;;
|
|
--broker-dir=*)
|
|
broker_dir="${1#*=}"
|
|
broker_dir_explicit="1"
|
|
shift
|
|
;;
|
|
--extauth)
|
|
extauth="1"
|
|
shift
|
|
;;
|
|
--no-extauth)
|
|
extauth="0"
|
|
shift
|
|
;;
|
|
--qortal)
|
|
rebuild_qortal="1"
|
|
shift
|
|
;;
|
|
--qortal=*)
|
|
rebuild_qortal="1"
|
|
qortal_branch="${1#*=}"
|
|
shift
|
|
;;
|
|
--qortal-branch)
|
|
rebuild_qortal="1"
|
|
qortal_branch_next="1"
|
|
shift
|
|
;;
|
|
--qortal-branch=*)
|
|
rebuild_qortal="1"
|
|
qortal_branch="${1#*=}"
|
|
shift
|
|
;;
|
|
--full)
|
|
full_rebuild="1"
|
|
rebuild_qortal="1"
|
|
shift
|
|
;;
|
|
--force-refresh-contexts)
|
|
force_refresh_contexts="1"
|
|
shift
|
|
;;
|
|
--finish-host-nextcloud-upgrade)
|
|
finish_host_nextcloud_upgrade="1"
|
|
shift
|
|
;;
|
|
--dry-run)
|
|
dry_run="1"
|
|
shift
|
|
;;
|
|
-h|--help)
|
|
usage
|
|
exit 0
|
|
;;
|
|
*)
|
|
echo "Unknown option: $1" >&2
|
|
usage
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
if [[ -z "${action}" ]]; then
|
|
usage
|
|
exit 1
|
|
fi
|
|
if [[ "${qortal_branch_next}" == "1" ]]; then
|
|
echo "--qortal-branch requires a value" >&2
|
|
exit 1
|
|
fi
|
|
if [[ "${mode}" != "auto" && "${mode}" != "ssl" && "${mode}" != "nossl" ]]; then
|
|
echo "Invalid mode: ${mode}" >&2
|
|
exit 1
|
|
fi
|
|
if [[ "${topology}" != "auto" && "${topology}" != "repo-devprod" && "${topology}" != "host-hybrid" ]]; then
|
|
echo "Invalid topology: ${topology}" >&2
|
|
exit 1
|
|
fi
|
|
if [[ -n "${qortal_branch}" ]] && ! git check-ref-format --branch "${qortal_branch}" >/dev/null 2>&1; then
|
|
echo "Invalid Qortal branch name: ${qortal_branch}" >&2
|
|
exit 1
|
|
fi
|
|
|
|
resolved_env_file="$(resolve_path "${env_file}")"
|
|
resolved_compose_file=""
|
|
if [[ -n "${compose_file}" ]]; then
|
|
resolved_compose_file="$(resolve_path "${compose_file}")"
|
|
elif [[ -f "${repo_root}/docker-compose.devprod.nossl.yml" ]]; then
|
|
resolved_compose_file="${repo_root}/docker-compose.devprod.nossl.yml"
|
|
elif [[ -f "${repo_root}/docker-compose.devprod.yml" ]]; then
|
|
resolved_compose_file="${repo_root}/docker-compose.devprod.yml"
|
|
fi
|
|
resolved_broker_dir="$(resolve_path "${broker_dir}")"
|
|
if [[ "${broker_dir_explicit}" == "0" && "${env_file_explicit}" == "1" && "$(basename "${resolved_env_file}")" == ".env" ]]; then
|
|
resolved_broker_dir="$(dirname "${resolved_env_file}")"
|
|
elif [[ "${broker_dir_explicit}" == "0" && "${compose_file_explicit}" == "1" && "$(basename "${resolved_compose_file}")" == "docker-compose.yml" ]]; then
|
|
resolved_broker_dir="$(dirname "${resolved_compose_file}")"
|
|
fi
|
|
|
|
if [[ "${action}" == "detect" ]]; then
|
|
args=(--repo-root "${repo_root}" --env-file "${resolved_env_file}" --text)
|
|
[[ -n "${resolved_compose_file}" ]] && args+=(--compose-file "${resolved_compose_file}")
|
|
run_or_print "${script_dir}/discover-cloud-topology.sh" "${args[@]}"
|
|
exit 0
|
|
fi
|
|
|
|
delegated_mode="$(infer_mode_from_compose "${resolved_compose_file}")"
|
|
|
|
case "${topology}" in
|
|
repo-devprod)
|
|
repo_devprod_cmd "${delegated_mode}"
|
|
exit 0
|
|
;;
|
|
host-hybrid)
|
|
host_hybrid_cmd
|
|
exit 0
|
|
;;
|
|
esac
|
|
|
|
if [[ "${broker_dir_explicit}" == "1" && -f "${resolved_broker_dir}/.env" && -f "${resolved_broker_dir}/docker-compose.yml" ]]; then
|
|
topology_id="host_nextcloud_plus_docker"
|
|
elif [[ "${env_file_explicit}" == "1" && "${resolved_env_file}" == "${resolved_broker_dir}/.env" ]]; then
|
|
topology_id="host_nextcloud_plus_docker"
|
|
elif [[ "${compose_file_explicit}" == "1" && "${resolved_compose_file}" == "${resolved_broker_dir}/docker-compose.yml" ]]; then
|
|
topology_id="host_nextcloud_plus_docker"
|
|
else
|
|
topology_id="$(detect_topology_id)"
|
|
fi
|
|
|
|
case "${topology_id}" in
|
|
host_nextcloud|host_nextcloud_plus_docker)
|
|
host_hybrid_cmd
|
|
;;
|
|
repo_docker_devprod|docker_compose_generic)
|
|
repo_devprod_cmd "${delegated_mode}"
|
|
;;
|
|
*)
|
|
if [[ -f "${resolved_broker_dir}/.env" && -f "${resolved_broker_dir}/docker-compose.yml" ]]; then
|
|
host_hybrid_cmd
|
|
elif [[ -f "${resolved_env_file}" ]]; then
|
|
repo_devprod_cmd "${delegated_mode}"
|
|
else
|
|
echo "Could not detect a supported NuQloud install." >&2
|
|
echo "Provide --env-file/--compose-file for repo devprod or --broker-dir for host-hybrid." >&2
|
|
exit 1
|
|
fi
|
|
;;
|
|
esac
|