#!/bin/sh
#
# install.sh: add the Restorable apt/rpm repo and install the agent.
# Modelled on Tailscale's install.sh. Primary entrypoint for D029.
#
# Canonical invocation (REST-1 auth-key flow):
#   curl -fsSL https://get.restorable.app | sudo bash                                     # no key
#   curl -fsSL https://get.restorable.app | sudo bash -s -- --auth-key=rsk_auth_...       # with key
#   RESTORABLE_AUTH_KEY=rsk_auth_... curl -fsSL https://get.restorable.app | sudo bash
#
# What this script does:
#   1. Require root (no sudo re-exec: run under `sudo bash` from the
#      start to avoid the `curl | bash` $0-is-"bash" re-exec pitfall).
#   2. Read /etc/os-release, pick apt or dnf per supported distro.
#      Anything else exits non-zero with a link to the manual-install
#      doc for deferred distros.
#   3. Import pub/restorable-release.gpg, write
#      /etc/apt/sources.list.d/restorable.list or
#      /etc/yum.repos.d/restorable.repo (both [signed-by=...] /
#      gpgcheck=1).
#   4. `apt-get install` / `dnf install restorable`.
#   5. If --auth-key was supplied, run `restorable init
#      --auth-key=KEY --orchestrator URL` as the restorable user
#      against the install root /var/lib/restorable, then start the
#      systemd unit.
#
# Env var surface (all optional):
#   RESTORABLE_AUTH_KEY=rsk_auth_...      Also accepted as --auth-key=.
#   RESTORABLE_ORCHESTRATOR_URL=https://app.restorable.app
#   RESTORABLE_BASE_URL=https://get.restorable.app  (testing only)
#
# POSIX-sh compatible on purpose: /bin/sh on Amazon Linux 2023 and
# Debian 12 is dash / bash respectively, both POSIX-compliant but
# bash features (arrays, [[ ]], etc.) aren't portable.

set -eu

BASE="${RESTORABLE_BASE_URL:-https://get.restorable.app}"
GPG_URL="$BASE/pub/restorable-release.gpg"
ORCH_URL="${RESTORABLE_ORCHESTRATOR_URL:-https://app.restorable.app}"

# Auth key resolution. Order: --auth-key=... flag, RESTORABLE_AUTH_KEY
# env. No positional fallback (the flag form is what the dashboard's
# install one-liner produces, and the env-var form is what CI / config-
# management drops in via shell expansion).
AUTH_KEY="${RESTORABLE_AUTH_KEY:-}"
for arg in "$@"; do
  case "$arg" in
    --auth-key=*) AUTH_KEY="${arg#--auth-key=}" ;;
  esac
done

log()  { printf '==> %s\n' "$*"; }
fail() { printf 'error: %s\n' "$*" >&2; exit 1; }

# ── Require root ───────────────────────────────────────────────────
if [ "$(id -u)" -ne 0 ]; then
  fail "install.sh must run as root. Retry with:
  curl -fsSL $BASE | sudo bash${AUTH_KEY:+ -s -- --auth-key=$AUTH_KEY}"
fi

# ── Distro detection ───────────────────────────────────────────────
[ -r /etc/os-release ] || fail "missing /etc/os-release; cannot detect distro"
. /etc/os-release

case "${ID:-}" in
  ubuntu|debian)
    MODE=apt
    SUITE=stable
    ;;
  rhel|rocky|almalinux|centos)
    MODE=dnf ;;
  # Fedora uses dnf + the same rpm we build for el9. Our Go agent is
  # linked without libc (netgo), and systemd / podman / fuse-overlayfs
  # package names match, so the el9 rpm resolves cleanly. Covers any
  # Fedora release that lands in the pattern (40, 41, 42, 43, ...).
  fedora) MODE=dnf ;;
  amzn)
    case "${VERSION_ID:-}" in
      2023) MODE=dnf ;;
      *) fail "unsupported amzn version: ${VERSION_ID:-unknown}
Manual install (raw binary + minisign verify): $BASE/docs/install/manual" ;;
    esac
    ;;
  *)
    fail "unsupported distro: ${ID:-unknown} ${VERSION_ID:-unknown}
Manual install (raw binary + minisign verify): $BASE/docs/install/manual"
    ;;
esac

log "detected $ID $VERSION_ID → $MODE ${SUITE:-el9}"

# Explicit runtime prerequisites. The package's Recommends: block
# lists these, but distro defaults for weak-dep resolution vary:
# apt honors them by default, dnf may not (RHEL 9's stock config
# skips them). Install explicitly for deterministic results.
RUNTIME_DEPS="podman fuse-overlayfs"

# ── apt path ────────────────────────────────────────────────────────
install_apt() {
  log "importing GPG release key"
  install -d -m 0755 /usr/share/keyrings
  curl -fsSL "$GPG_URL" \
    | gpg --dearmor --batch --yes -o /usr/share/keyrings/restorable.gpg
  chmod 0644 /usr/share/keyrings/restorable.gpg

  log "writing /etc/apt/sources.list.d/restorable.list"
  cat > /etc/apt/sources.list.d/restorable.list <<EOF
deb [signed-by=/usr/share/keyrings/restorable.gpg] $BASE/apt $SUITE main
EOF

  log "apt-get update + install"
  apt-get update -qq
  # --install-recommends makes the behavior explicit regardless of
  # APT::Install-Recommends defaults (usually true on apt, but not
  # on every base image).
  DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --install-recommends \
    restorable $RUNTIME_DEPS
}

# ── dnf path ────────────────────────────────────────────────────────
install_dnf() {
  log "writing /etc/yum.repos.d/restorable.repo"
  cat > /etc/yum.repos.d/restorable.repo <<EOF
[restorable]
name=Restorable
baseurl=$BASE/rpm/el9/\$basearch
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=$GPG_URL
EOF

  log "dnf install"
  # --setopt=install_weak_deps=True forces Recommends to be pulled
  # in. Useful on RHEL 9 where the stock config sets this False,
  # so podman / fuse-overlayfs don't land otherwise. Listing the
  # runtime deps explicitly is belt-and-suspenders.
  dnf install -y -q --setopt=install_weak_deps=True \
    restorable $RUNTIME_DEPS
}

case "$MODE" in
  apt) install_apt ;;
  dnf) install_dnf ;;
esac

# ── Print fingerprint for customer cross-check ─────────────────────
#
# gpg is part of the GPG path directly; on apt hosts we just imported
# it. On dnf hosts, `dnf install` only imports the key into rpmdb, so
# we fetch + show fingerprint out-of-band for visibility.
if command -v gpg >/dev/null 2>&1; then
  printf '==> GPG key fingerprint (cross-check at restorable.app/trust):\n'
  curl -fsSL "$GPG_URL" | gpg --show-keys --with-fingerprint 2>/dev/null \
    | awk '/^ / { printf "    %s\n", $0 }' || true
fi

# ── Optional auto-attach ───────────────────────────────────────────
if [ -n "$AUTH_KEY" ]; then
  log "running restorable init with auth-key"
  # cd to a directory the restorable user can read; avoids chdir
  # failures when the installer is driven from /root or another
  # mode-0700 cwd. --skip-doctor: the agent runs doctor itself once
  # the systemd unit starts, on the customer's environment; running
  # it here under the install context doesn't add signal.
  ( cd /var/lib/restorable && \
    sudo -u restorable /usr/bin/restorable init \
      --root /var/lib/restorable \
      --auth-key="$AUTH_KEY" \
      --orchestrator "$ORCH_URL" \
      --skip-doctor )
  log "starting service"
  systemctl enable --now restorable || true
else
  cat <<EOF

Installed. Next steps:
  1. Create an auth key in the dashboard (Add machine).
  2. Attach this host:
       sudo -u restorable /usr/bin/restorable init \\
         --auth-key=rsk_auth_... \\
         --orchestrator $ORCH_URL
     Or run interactively:
       sudo -u restorable /usr/bin/restorable init
       (prints an attach URL; operator approves from the dashboard)
  3. Start the service:
       sudo systemctl enable --now restorable

Upgrades: sudo $MODE upgrade restorable (or unattended-upgrades
/ dnf-automatic running on your existing cadence).

Docs: $BASE/docs/install/quickstart
EOF
fi
