uvlava/services/artifacts-stack/apply.sh
Natalie 5748757345 infra(services): one-shot apply.sh for the producer-separated artifacts stack
Backs up, ships compose/Caddyfile/verdaccio configs, migrates the shared registry
into verdaccio-ct, docker compose up, caddy reload, verifies npm.{ct,mc,quinn}.
Idempotent. Run via ! (shared multi-org host, not auto-mode).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 08:07:04 -04:00

61 lines
3.4 KiB
Bash
Executable file

#!/usr/bin/env bash
# One-shot apply for the artifacts-host service stack (forge + producer-separated
# npm). Run from a machine with mesh/SSH reach: ./apply.sh
#
# It ships this dir's compose/Caddyfile/verdaccio configs to /opt/services on the
# artifacts host, lays out per-producer verdaccio dirs, migrates the shared
# registry's packages+auth into verdaccio-ct, brings the stack up, reloads the
# edge, and verifies. Idempotent + backs up before changing anything.
#
# The host is the SHARED multi-org artifacts box, so auto-mode can't run this for
# you — invoke it yourself (e.g. `! ./apply.sh` in-session).
set -euo pipefail
HOST="${ARTIFACTS_HOST:-134.199.243.61}"
JUMP="${ARTIFACTS_JUMP:-quinn-vps}"
KEY="${ARTIFACTS_KEY:-$HOME/.ssh/id_ed25519_1984}"
REMOTE="/opt/services"
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SSH=(ssh -J "$JUMP" -i "$KEY" -o StrictHostKeyChecking=accept-new "root@$HOST")
rsh="ssh -J $JUMP -i $KEY -o StrictHostKeyChecking=accept-new"
say() { printf '\033[0;32m▸\033[0m %s\n' "$1"; }
say "Reachability check ($HOST via $JUMP)"
"${SSH[@]}" 'echo ok' >/dev/null || { echo "cannot reach root@$HOST via $JUMP"; exit 1; }
say "Backing up current compose + Caddyfile on the host"
"${SSH[@]}" "cd $REMOTE && cp -a docker-compose.yml docker-compose.yml.bak.\$(date +%s) 2>/dev/null || true; cp -a Caddyfile Caddyfile.bak.\$(date +%s) 2>/dev/null || true"
say "Laying out per-producer verdaccio dirs + migrating the shared registry into ct"
"${SSH[@]}" "cd $REMOTE
for p in ct mc quinn; do mkdir -p verdaccio-\$p/storage verdaccio-\$p/conf; done
# Migrate existing packages + htpasswd once (don't clobber a prior run).
if [ ! -e verdaccio-ct/storage/.migrated ]; then
if [ -d verdaccio/storage ]; then cp -a verdaccio/storage/. verdaccio-ct/storage/ 2>/dev/null || true
elif [ -d verdaccio ]; then cp -a verdaccio/. verdaccio-ct/storage/ 2>/dev/null || true; fi
touch verdaccio-ct/storage/.migrated
fi"
say "Shipping compose, Caddyfile, and verdaccio configs"
rsync -az -e "$rsh" "$DIR/docker-compose.yml" "root@$HOST:$REMOTE/docker-compose.yml"
rsync -az -e "$rsh" "$DIR/Caddyfile" "root@$HOST:$REMOTE/Caddyfile"
rsync -az -e "$rsh" "$DIR/verdaccio-ct.config.yaml" "root@$HOST:$REMOTE/verdaccio-ct/conf/config.yaml"
rsync -az -e "$rsh" "$DIR/verdaccio-downstream.config.yaml" "root@$HOST:$REMOTE/verdaccio-mc/conf/config.yaml"
rsync -az -e "$rsh" "$DIR/verdaccio-downstream.config.yaml" "root@$HOST:$REMOTE/verdaccio-quinn/conf/config.yaml"
say "Bringing the stack up + reloading the edge"
"${SSH[@]}" "cd $REMOTE
docker compose up -d
docker exec services-caddy-1 caddy validate --config /etc/caddy/Caddyfile
docker exec services-caddy-1 caddy reload --config /etc/caddy/Caddyfile"
say "Verifying"
sleep 3
"${SSH[@]}" '
echo -n " npm.ct ping: "; curl -fsS https://npm.ct.uvlava.com/-/ping >/dev/null && echo ok || echo FAIL
echo -n " ct @cocotte: "; curl -fsS https://npm.ct.uvlava.com/@cocotte/ai-harness >/dev/null && echo "serves @cocotte/ai-harness" || echo "(not found — check migration)"
echo -n " mc proxy: "; curl -fsS https://npm.mc.uvlava.com/-/ping >/dev/null && echo ok || echo "FAIL (npm.mc DNS?)"
echo -n " quinn proxy: "; curl -fsS https://npm.quinn.uvlava.com/-/ping >/dev/null && echo ok || echo "FAIL (npm.quinn DNS?)"
'
say "Done. Point consumers at https://npm.ct.uvlava.com/ (see README)."