70 lines
2.9 KiB
Bash
70 lines
2.9 KiB
Bash
#!/usr/bin/env bash
|
|||
|
|
# FULL reset of the runtime — keeps ONLY the shared challenge images.
|
||
|
|
#
|
||
|
|
# Removes: every team container, every team docker network, every anonymous/
|
||
|
|
# named volume, every per-team receiver systemd unit, and all team directories
|
||
|
|
# (state, flags, credentials, compose). KEEPS: services-* images (the
|
||
|
|
# challenges themselves), the panel, the global receiver, the challenge sources
|
||
|
|
# in services/, and the registry.
|
||
|
|
#
|
||
|
|
# This is the "purge everything except the challenges" path the organiser asked
|
||
|
|
# for after passwords drifted: fresh containers get fresh /etc/shadow state, so
|
||
|
|
# no stale credential can survive.
|
||
|
|
set -uo pipefail
|
||
|
|
BASE=/opt/gemastik18-final
|
||
|
|
TEAMS=$BASE/teams
|
||
|
|
|
||
|
|
echo "=== [1/6] stop per-team receivers + remove units ==="
|
||
|
|
for u in $(systemctl list-unit-files 'gemastik-receiver-team*.service' 2>/dev/null \
|
||
|
|
| awk '/gemastik-receiver-team/{print $1}'); do
|
||
|
|
systemctl disable --now "$u" >/dev/null 2>&1
|
||
|
|
rm -f "/etc/systemd/system/$u"
|
||
|
|
echo " removed $u"
|
||
|
|
done
|
||
|
|
systemctl daemon-reload
|
||
|
|
|
||
|
|
echo "=== [2/6] compose down for every team (before deleting dirs) ==="
|
||
|
|
for d in "$TEAMS"/team*/services; do
|
||
|
|
[ -d "$d" ] || continue
|
||
|
|
idx=$(basename "$(dirname "$d")")
|
||
|
|
echo " compose down $idx"
|
||
|
|
(cd "$d" && docker compose -p "$idx" -f docker-compose.yml down -v --remove-orphans 2>&1 | tail -1)
|
||
|
|
done
|
||
|
|
|
||
|
|
echo "=== [3/6] force-remove any surviving team containers ==="
|
||
|
|
left=$(docker ps -aq --filter 'name=_container_team' | wc -l)
|
||
|
|
echo " found $left"
|
||
|
|
[ "$left" -gt 0 ] && docker rm -f $(docker ps -aq --filter 'name=_container_team') >/dev/null 2>&1
|
||
|
|
|
||
|
|
echo "=== [4/6] remove team networks + stray volumes ==="
|
||
|
|
for n in $(docker network ls --format '{{.Name}}' | grep -E '^team[0-9]+_default$' || true); do
|
||
|
|
docker network rm "$n" >/dev/null 2>&1 && echo " network $n"
|
||
|
|
done
|
||
|
|
# anonymous + team-scoped volumes (challenge DB state lives here)
|
||
|
|
anon=$(docker volume ls -q --filter dangling=true | wc -l)
|
||
|
|
echo " dangling volumes: $anon"
|
||
|
|
[ "$anon" -gt 0 ] && docker volume prune -f >/dev/null 2>&1 && echo " pruned"
|
||
|
|
for v in $(docker volume ls --format '{{.Name}}' | grep -E '^team[0-9]+' || true); do
|
||
|
|
docker volume rm "$v" >/dev/null 2>&1 && echo " volume $v"
|
||
|
|
done
|
||
|
|
|
||
|
|
echo "=== [5/6] delete team dirs + ledgers ==="
|
||
|
|
rm -rf "$TEAMS"/team*
|
||
|
|
rm -f "$TEAMS"/leaderboard.json "$TEAMS"/points.json "$TEAMS"/attacks.json
|
||
|
|
echo " team dirs now: $(ls -d "$TEAMS"/team* 2>/dev/null | wc -l)"
|
||
|
|
|
||
|
|
echo "=== [6/6] drop team domains from Traefik ==="
|
||
|
|
cd "$BASE/panel" && python3 -c "
|
||
|
|
import sys; sys.path.insert(0,'.')
|
||
|
|
import teams
|
||
|
|
print(' ', teams.ensure_team_domains())
|
||
|
|
"
|
||
|
|
# the platform-level receiver is separate and must keep running
|
||
|
|
systemctl restart gemastik-panel 2>/dev/null
|
||
|
|
echo " panel: $(systemctl is-active gemastik-panel)"
|
||
|
|
|
||
|
|
echo "=== done ==="
|
||
|
|
docker ps --format '{{.Names}}' | grep -c '_container_team' || echo " team containers: 0"
|
||
|
|
docker images --format '{{.Repository}}' | grep -c '^services-' || true
|
||
|
|
df -h / | tail -1
|