#!/bin/sh set -eu default_release_url="https://vastora.petauron.com/vastora-center-install.tar.gz" release_url="$default_release_url" release_resolve="" install_dir="/opt/vastora/center" coordinated_agent_migration=no expected_version="" usage() { cat <<'EOF' Usage: install.sh center [--release-url HTTPS_URL] [--release-resolve HOST:PORT:ADDRESS] [--install-dir DIR] [--expected-version VERSION] [--coordinated-agent-migration] [-- SETUP_OPTIONS] install.sh center uninstall [--release-url HTTPS_URL] [--install-dir DIR] Installs the verified Vastora Center release bundle on loopback, then prints an SSH tunnel command for the first-run wizard. Agent commands come from Center. Examples: curl -LsSf https://vastora.petauron.com/install.sh | sudo sh -s -- center curl -LsSf https://vastora.petauron.com/install.sh | sudo sh -s -- center uninstall ./install.sh center -- --ssh-host center.example.com EOF } if [ "${1:-}" = "-h" ] || [ "${1:-}" = "--help" ]; then usage exit 0 fi if [ "${1:-}" != "center" ]; then echo "Choose 'center'. Agents are installed with the one-time command generated by Center." >&2 usage >&2 exit 2 fi shift operation="install" if [ "${1:-}" = "uninstall" ]; then operation="uninstall" shift fi while [ "$#" -gt 0 ]; do case "$1" in --release-url) [ "$#" -ge 2 ] || { echo "--release-url requires a value." >&2; exit 2; } release_url="$2" shift 2 ;; --release-resolve) [ "$#" -ge 2 ] || { echo "--release-resolve requires a value." >&2; exit 2; } release_resolve="$2" shift 2 ;; --install-dir) [ "$#" -ge 2 ] || { echo "--install-dir requires a value." >&2; exit 2; } install_dir="$2" shift 2 ;; --expected-version) [ "$#" -ge 2 ] || { echo "--expected-version requires a value." >&2; exit 2; } expected_version="$2" shift 2 ;; --coordinated-agent-migration) coordinated_agent_migration=yes shift ;; --) shift; break ;; *) break ;; esac done if [ "$operation" = "uninstall" ] && [ "$#" -gt 0 ]; then echo "Unknown uninstall argument: $1" >&2 echo "Run 'center uninstall' without cleanup flags; the terminal menu provides every option." >&2 exit 2 fi if [ "$operation" = "uninstall" ] && [ "$coordinated_agent_migration" = yes ]; then echo "The migration option cannot be used for uninstall." >&2 exit 2 fi if [ "$(uname -s)" != "Linux" ]; then echo "Vastora Center installation currently supports Linux hosts." >&2 exit 1 fi case "$(uname -m)" in x86_64|amd64) ;; aarch64|arm64) ;; *) echo "Vastora Center supports Ubuntu 24.04 on x86_64 and ARM64." >&2; exit 1 ;; esac if [ "$(id -u)" -ne 0 ]; then echo "Run the Center installer with sudo." >&2 exit 1 fi case "$release_url" in https://*) ;; *) echo "The Center release URL must use HTTPS." >&2; exit 2 ;; esac if [ -n "$release_resolve" ]; then case "$release_resolve" in *:*:*) ;; *) echo "The release DNS pin is invalid." >&2; exit 2 ;; esac if printf '%s\n' "$release_resolve" | grep -Eq '[[:space:]]'; then echo "The release DNS pin is invalid." >&2 exit 2 fi fi case "$install_dir" in /*) ;; *) echo "The installation directory must be an absolute path." >&2; exit 2 ;; esac for required in curl tar mktemp install awk dirname grep mv; do if ! command -v "$required" >/dev/null 2>&1; then echo "Required command is not installed: $required" >&2 exit 1 fi done if [ -n "$expected_version" ] && ! printf '%s\n' "$expected_version" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$'; then echo "The expected Center version is invalid." >&2 exit 2 fi if command -v sha256sum >/dev/null 2>&1; then digest_command="sha256sum" elif command -v shasum >/dev/null 2>&1; then digest_command="shasum -a 256" else echo "Install sha256sum or shasum, then run the same command again." >&2 exit 1 fi temporary_dir="$(mktemp -d "${TMPDIR:-/tmp}/vastora-center-install.XXXXXX")" archive="$temporary_dir/vastora-center-install.tar.gz" checksum="$temporary_dir/vastora-center-install.tar.gz.sha256" staging="" cleanup() { rm -rf "$temporary_dir" if [ -n "$staging" ] && [ -d "$staging" ]; then rm -rf "$staging" fi } trap cleanup EXIT HUP INT TERM echo "Downloading the Vastora Center release bundle..." if [ -n "$release_resolve" ]; then if ! curl --proto '=https' --tlsv1.2 -fsS --resolve "$release_resolve" "$release_url" -o "$archive"; then echo "No installable Center release was found. Check the release URL and try again." >&2 exit 1 fi elif ! curl --proto '=https' --proto-redir '=https' --tlsv1.2 -fsSL "$release_url" -o "$archive"; then echo "No installable Center release was found. Check the release URL and try again." >&2 exit 1 fi if [ -n "$release_resolve" ]; then if ! curl --proto '=https' --tlsv1.2 -fsS --resolve "$release_resolve" "$release_url.sha256" -o "$checksum"; then echo "The release checksum could not be downloaded; nothing was installed." >&2 exit 1 fi elif ! curl --proto '=https' --proto-redir '=https' --tlsv1.2 -fsSL "$release_url.sha256" -o "$checksum"; then echo "The release checksum could not be downloaded; nothing was installed." >&2 exit 1 fi expected_digest="$(awk 'NR == 1 {print tolower($1)}' "$checksum")" actual_digest="$($digest_command "$archive" | awk 'NR == 1 {print tolower($1)}')" if [ -z "$expected_digest" ] || [ "$expected_digest" != "$actual_digest" ]; then echo "The Center release failed its SHA-256 integrity check; nothing was installed." >&2 exit 1 fi if ! tar -tzf "$archive" | while IFS= read -r entry; do case "$entry" in /*|..|./..|../*|*/../*|*/..) echo "Unsafe archive entry: $entry" >&2; exit 1 ;; esac done; then echo "The Center release archive is unsafe; nothing was installed." >&2 exit 1 fi if ! tar -tvzf "$archive" | awk '$1 !~ /^[-d]/ {exit 1}'; then echo "The Center release archive contains unsupported links or special files." >&2 exit 1 fi install -d -m 0755 "$(dirname "$install_dir")" staging="$(mktemp -d "${install_dir}.new.XXXXXX")" tar -xzf "$archive" -C "$staging" for required_file in install.sh setup.sh upgrade.sh uninstall.sh install-host-cli.sh install-update-service.sh update-center.sh compare-semver.awk compose.yaml release.env; do if [ ! -f "$staging/$required_file" ]; then echo "The Center release is incomplete: missing $required_file" >&2 exit 1 fi done bundle_version="$(awk -F= '$1 == "VASTORA_VERSION" {sub(/^[^=]*=/, ""); print; exit}' "$staging/release.env")" if ! printf '%s\n' "$bundle_version" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$'; then echo "The Center release contains an invalid version; nothing was installed." >&2 exit 1 fi if [ -n "$expected_version" ] && [ "$bundle_version" != "$expected_version" ]; then echo "The Center release version does not match the requested update; nothing was installed." >&2 exit 1 fi chmod 0755 "$staging/setup.sh" chmod 0755 "$staging/upgrade.sh" chmod 0755 "$staging/uninstall.sh" chmod 0755 "$staging/install-host-cli.sh" chmod 0755 "$staging/install-update-service.sh" chmod 0755 "$staging/update-center.sh" if [ "$operation" = "uninstall" ]; then "$staging/uninstall.sh" --install-dir "$install_dir" exit 0 fi if [ -d "$install_dir" ]; then if [ ! -f "$install_dir/.env" ] || [ ! -f "$install_dir/release.env" ]; then echo "$install_dir exists but is not a managed Center installation; no files were changed." >&2 exit 1 fi installed_version="$(awk -F= '$1 == "VASTORA_VERSION" {sub(/^[^=]*=/, ""); print; exit}' "$install_dir/release.env")" if ! printf '%s\n' "$installed_version" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$'; then echo "The installed Center version is invalid; no files were changed." >&2 exit 1 fi if [ "$(awk -f "$staging/compare-semver.awk" "$bundle_version" "$installed_version")" = "-1" ]; then echo "Refusing to downgrade Center from $installed_version to $bundle_version; no files were changed." >&2 exit 1 fi echo "Existing Center installation found; upgrading it in place..." if [ "$coordinated_agent_migration" = yes ]; then "$staging/upgrade.sh" --install-dir "$install_dir" --coordinated-agent-migration else "$staging/upgrade.sh" --install-dir "$install_dir" fi exit 0 fi if [ "$coordinated_agent_migration" = yes ]; then echo "The migration option requires an existing Center installation." >&2 exit 2 fi if [ -e "$install_dir" ]; then echo "$install_dir exists but is not a directory; no files were changed." >&2 exit 1 fi mv "$staging" "$install_dir" staging="" echo "Verified Center files installed at $install_dir" rm -rf "$temporary_dir" trap - EXIT HUP INT TERM cd "$install_dir" exec "$install_dir/setup.sh" "$@"