| 1 | #!/bin/sh |
| 2 | set -eu |
| 3 | |
| 4 | instance=${1:?usage: tools/import-source-index.sh clover-source-of-truth-preview-XXXXXXXX} |
| 5 | printf '%s\n' "$instance" | grep -Eq '^clover-source-of-truth-preview-[0-9a-f]{8}$' || { |
| 6 | echo 'Expected a Clover Source of Truth preview ID' >&2 |
| 7 | exit 1 |
| 8 | } |
| 9 | |
| 10 | source_host=${STUDIO_MIGRATION_SOURCE:-zenith} |
| 11 | target_host=${STUDIO_DEPLOY_HOST:-root@127.0.0.1} |
| 12 | target_port=${STUDIO_DEPLOY_PORT:-2222} |
| 13 | root="/srv/staging/$instance/data" |
| 14 | mount="/srv/staging/$instance" |
| 15 | source_id=$(ssh -p "$target_port" "$target_host" "python3 -c 'import json; print(json.load(open(\"/var/lib/studio/stages/$instance.json\"))[\"sourceId\"])'") |
| 16 | test "$source_id" = clover-source-of-truth || { echo 'Preview belongs to another service' >&2; exit 1; } |
| 17 | dataset=$(ssh -p "$target_port" "$target_host" "findmnt -n -o SOURCE --mountpoint $mount") |
| 18 | case $dataset in */staging/"$instance") ;; *) echo 'Preview dataset is not mounted' >&2; exit 1 ;; esac |
| 19 | |
| 20 | scratch=$(mktemp -d) |
| 21 | source_backup= |
| 22 | cleanup() { |
| 23 | rm -rf "$scratch" |
| 24 | if [ -n "$source_backup" ]; then |
| 25 | ssh "$source_host" "rm -rf '$source_backup'" |
| 26 | fi |
| 27 | } |
| 28 | trap cleanup EXIT |
| 29 | |
| 30 | source_backup=$(ssh "$source_host" sh -s <<'REMOTE' |
| 31 | set -eu |
| 32 | out=$(mktemp -d /tmp/studio-source-index-XXXXXX) |
| 33 | trap 'rm -rf "$out"' EXIT |
| 34 | source='/mnt/storage1/clover/Documents/Config/paper clover/cache.sqlite' |
| 35 | sqlite3 -readonly "$source" ".backup '$out/cache.sqlite'" |
| 36 | test "$(sqlite3 -readonly "$out/cache.sqlite" 'PRAGMA integrity_check;')" = ok |
| 37 | trap - EXIT |
| 38 | printf '%s\n' "$out" |
| 39 | REMOTE |
| 40 | ) |
| 41 | rsync -a "$source_host:$source_backup/cache.sqlite" "$scratch/cache.sqlite" |
| 42 | python3 - "$scratch/cache.sqlite" <<'PY' |
| 43 | import sqlite3 |
| 44 | import sys |
| 45 | |
| 46 | db = sqlite3.connect('file:' + sys.argv[1] + '?mode=ro&immutable=1', uri=True) |
| 47 | assert db.execute('PRAGMA integrity_check').fetchone()[0] == 'ok' |
| 48 | PY |
| 49 | |
| 50 | ssh -p "$target_port" "$target_host" "NOMAD_TOKEN=\$(cat /var/lib/studio/nomad.token) nomad job stop -yes $instance" |
| 51 | snapshot="$dataset@before-source-index-import-$(date +%s)-$$" |
| 52 | ssh -p "$target_port" "$target_host" "set -eu; for i in \$(seq 1 30); do running=\$(curl -fsS -H \"X-Nomad-Token: \$(cat /var/lib/studio/nomad.token)\" http://127.0.0.1:4646/v1/job/$instance/allocations | python3 -c 'import json,sys; print(sum(a[\"ClientStatus\"] == \"running\" for a in json.load(sys.stdin)))'); test \"\$running\" = 0 && break; sleep 2; done; test \"\$running\" = 0; zfs snapshot $snapshot" |
| 53 | |
| 54 | rsync -a -e "ssh -p $target_port" "$scratch/cache.sqlite" "$target_host:$root/cache.sqlite" |
| 55 | owner=$(ssh -p "$target_port" "$target_host" "python3 -c 'import json; print(json.load(open(\"/var/lib/studio/identities.json\"))[\"clover-source-of-truth\"])'") |
| 56 | ssh -p "$target_port" "$target_host" "chown $owner:$owner $root/cache.sqlite; rm -f $root/cache.sqlite-wal $root/cache.sqlite-shm $root/db-snapshot.sqlite" |
| 57 | drift=$(rsync -rnc --out-format='%n' -e "ssh -p $target_port" "$scratch/cache.sqlite" "$target_host:$root/cache.sqlite") |
| 58 | test -z "$drift" || { echo "Index copy differs from source backup; restore $snapshot" >&2; exit 1; } |
| 59 | |
| 60 | python3 "$(dirname "$0")/deploy.py" stage clover-source-of-truth |
| 61 | ssh -p "$target_port" "$target_host" "python3 - <<'PY' |
| 62 | import sqlite3 |
| 63 | source = sqlite3.connect('file:$root/cache.sqlite?mode=ro', uri=True) |
| 64 | assert source.execute('PRAGMA integrity_check').fetchone()[0] == 'ok' |
| 65 | for table in ('media_files', 'derived_files', 'derived_refs'): |
| 66 | print(table, source.execute('SELECT count(*) FROM ' + table).fetchone()[0]) |
| 67 | PY" |
| 68 | echo "Imported the live SQLite index into $instance; previous dataset: $snapshot" |