diff --git a/ansible/roles/gitea_runner/templates/runner-cleanup.sh.j2 b/ansible/roles/gitea_runner/templates/runner-cleanup.sh.j2 index 23f6d25..d438221 100644 --- a/ansible/roles/gitea_runner/templates/runner-cleanup.sh.j2 +++ b/ansible/roles/gitea_runner/templates/runner-cleanup.sh.j2 @@ -47,30 +47,54 @@ remove_stopped_containers() { # Remove unused images older than $1 ("all" = no age limit). The keep-list # (warm base layers) and leased images are never removed; images referenced -# by any container are refused by the daemon anyway. +# by any container are refused by the daemon anyway. `docker images` has no +# label formatter, so the lease is checked via inspect per candidate. remove_old_images() { local until="$1" - docker image prune -f --filter "label!=${LEASE_UNTIL_LABEL}" >/dev/null 2>&1 || true + docker image prune -f >/dev/null 2>&1 || true local filters=(--filter "dangling=false") [[ "$until" != "all" ]] && filters+=(--filter "until=${until}") { timeout 30 docker images "${filters[@]}" \ - --format '{% raw %}{{.ID}}|{{.Repository}}:{{.Tag}}|{{.Label "org.oblachno.lease-until"}}{% endraw %}' \ + --format '{% raw %}{{.ID}}|{{.Repository}}:{{.Tag}}{% endraw %}' \ 2>/dev/null || true; } \ - | while IFS='|' read -r iid ref lease_until; do + | while IFS='|' read -r iid ref; do [[ -z "$iid" || "$ref" == *""* ]] && continue [[ -n "$KEEP_IMAGES_RE" && "$ref" =~ $KEEP_IMAGES_RE ]] && continue + local lease_until + lease_until=$(docker image inspect "$iid" \ + --format '{% raw %}{{index .Config.Labels "org.oblachno.lease-until"}}{% endraw %}' \ + 2>/dev/null || true) lease_active "$lease_until" && continue docker image rm "$iid" >/dev/null 2>&1 || true done } +# Reclaim volumes/networks whose lease expired. The prune filters below +# skip every leased object (label!=); this pass removes the expired ones. +reclaim_expired_leases() { + timeout 20 docker volume ls -q --filter "label=${LEASE_UNTIL_LABEL}" 2>/dev/null \ + | while read -r vol; do + lease_until=$(docker volume inspect "$vol" \ + --format '{% raw %}{{index .Labels "org.oblachno.lease-until"}}{% endraw %}' \ + 2>/dev/null || true) + lease_active "$lease_until" || docker volume rm "$vol" >/dev/null 2>&1 || true + done + timeout 20 docker network ls -q --filter "label=${LEASE_UNTIL_LABEL}" 2>/dev/null \ + | while read -r net; do + lease_until=$(docker network inspect "$net" \ + --format '{% raw %}{{index .Labels "org.oblachno.lease-until"}}{% endraw %}' \ + 2>/dev/null || true) + lease_active "$lease_until" || docker network rm "$net" >/dev/null 2>&1 || true + done +} + case "$TIER" in routine) remove_stopped_containers aged remove_old_images "{{ gitea_runner_prune_until }}" - docker volume prune -f \ - --filter "label!=${LEASE_UNTIL_LABEL}" \ - --filter "until={{ gitea_runner_prune_until }}" >/dev/null 2>&1 || true + # Anonymous volumes only at routine tier; named volumes may belong + # to a job between create/attach steps. + docker volume prune -f --filter "label!=${LEASE_UNTIL_LABEL}" >/dev/null 2>&1 || true docker network prune -f \ --filter "label!=${LEASE_UNTIL_LABEL}" \ --filter "until={{ gitea_runner_prune_until }}" >/dev/null 2>&1 || true @@ -79,9 +103,7 @@ case "$TIER" in pressure) remove_stopped_containers aged remove_old_images "1h" - docker volume prune -f \ - --filter "label!=${LEASE_UNTIL_LABEL}" \ - --filter "until=1h" >/dev/null 2>&1 || true + docker volume prune -f --filter "label!=${LEASE_UNTIL_LABEL}" >/dev/null 2>&1 || true docker network prune -f \ --filter "label!=${LEASE_UNTIL_LABEL}" \ --filter "until=1h" >/dev/null 2>&1 || true @@ -91,7 +113,7 @@ case "$TIER" in # Implements: REQ-3 — age limits dropped, ownership still honored. remove_stopped_containers all remove_old_images all - docker volume prune -f --filter "label!=${LEASE_UNTIL_LABEL}" >/dev/null 2>&1 || true + docker volume prune -af --filter "label!=${LEASE_UNTIL_LABEL}" >/dev/null 2>&1 || true docker network prune -f --filter "label!=${LEASE_UNTIL_LABEL}" >/dev/null 2>&1 || true docker builder prune -af >/dev/null 2>&1 || true ;; @@ -100,3 +122,5 @@ case "$TIER" in exit 2 ;; esac + +reclaim_expired_leases