#!/bin/bash
# CodeNavi first boot on a Google Cloud GPU VM (CN-815) - the startup script named in
# docs/cloud-gpu.md, "Google Cloud in one step". Google runs it as root at EVERY boot;
# it installs once (a finished install is left alone) and logs to
# /var/log/codenavi-first-boot.log. Needs these instance metadata keys:
#   codenavi-token   the 32-character install token (portal "Install CodeNavi" / trial email)
#   codenavi-repo    https URL of the repository to index (read token in the URL for a private one)
#   codenavi-name    optional - the codebase name shown in the UI (default: the repo's folder name)
# Image: the Deep Learning VM family common-cu129-ubuntu-2204-nvidia-580 - driver and NVIDIA
# container toolkit on board, no Docker engine (installed here from Docker's own repository).
set -u
exec >> /var/log/codenavi-first-boot.log 2>&1
MD=http://metadata.google.internal/computeMetadata/v1/instance/attributes
md() { curl -sf -H 'Metadata-Flavor: Google' "$MD/$1"; }

if [ -e /opt/codenavi/codenavi/.env ]; then echo "codenavi: already installed - nothing to do ($(date -Is))"; exit 0; fi
echo "codenavi first boot: $(date -Is)"

# 1. The GPU driver. With install-nvidia-driver=True the image installs it at first boot;
#    wait for it rather than racing it.
for i in $(seq 1 120); do nvidia-smi -L > /dev/null 2>&1 && break; sleep 10; done
nvidia-smi -L || echo "WARN: no NVIDIA driver after 20 min - continuing; the installer will say CPU-only"

# 2. Docker CE from Docker's repository. Do NOT add NVIDIA's container-toolkit repository
#    on this image - its pinned toolkit conflicts with the newer package; the preinstalled
#    toolkit is fine (see the Google Cloud section of the docs).
if ! command -v docker > /dev/null 2>&1; then
    export DEBIAN_FRONTEND=noninteractive
    apt-get update -q
    apt-get install -y -q ca-certificates curl git
    install -m 0755 -d /etc/apt/keyrings
    curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
    . /etc/os-release
    echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $VERSION_CODENAME stable" \
        > /etc/apt/sources.list.d/docker.list
    apt-get update -q
    apt-get install -y -q docker-ce docker-ce-cli containerd.io docker-compose-plugin
fi
nvidia-ctk runtime configure --runtime=docker && systemctl restart docker
for i in $(seq 1 30); do docker info > /dev/null 2>&1 && break; sleep 5; done

# 3. A login user that owns the install (Google creates YOUR user at first ssh, after this
#    script has run, so the install cannot live under it). Home is /opt/codenavi.
id codenavi > /dev/null 2>&1 || useradd -m -d /opt/codenavi -s /bin/bash codenavi
usermod -aG docker codenavi

TOKEN="$(md codenavi-token || true)"; REPO="$(md codenavi-repo || true)"; NAME="$(md codenavi-name || true)"
if [ -z "$TOKEN" ] || [ -z "$REPO" ]; then
    echo "ERROR: instance metadata codenavi-token and codenavi-repo are required - add them and reset the VM"
    exit 1
fi

# 4. The same install a person would run from the docs, unattended, as codenavi. Its output
#    ends with the MCP auth token, so it goes to a file only that user (and root) can read.
cat > /opt/codenavi/first-boot.sh <<'INNER'
umask 077
cd "$HOME" || exit 1
NAME="$CN_NAME"
[ -n "$NAME" ] || NAME="$(basename "$CN_REPO" .git | tr '[:upper:]' '[:lower:]' | tr -cd 'a-z0-9_-')"
mkdir -p "$HOME/repos"
git clone --depth 1 "$CN_REPO" "$HOME/repos/$NAME" || echo "git clone failed - fix the URL, then: git clone <url> ~/repos/$NAME && cd ~/codenavi && ./setup.sh"
export CODEBASE_PATH="$HOME/repos/$NAME" CODEBASE_NAME="$NAME"
curl -fsSL "https://codenavi.com/trial/install/$CN_TOKEN" | sh
echo "=== install exit=$? $(date -Is) ==="
INNER
chown codenavi:codenavi /opt/codenavi/first-boot.sh
chmod 700 /opt/codenavi/first-boot.sh
sudo -iu codenavi env CN_TOKEN="$TOKEN" CN_REPO="$REPO" CN_NAME="$NAME" \
    bash -c 'umask 077; "$HOME/first-boot.sh" > "$HOME/codenavi-install.log" 2>&1'
rm -f /opt/codenavi/first-boot.sh
echo "codenavi first boot done: $(date -Is)"
