Skip to content

Instantly share code, notes, and snippets.

@thomasjm
Last active April 2, 2026 00:32
Show Gist options
  • Select an option

  • Save thomasjm/6a2d60e3233fa55bc7765c2426784b33 to your computer and use it in GitHub Desktop.

Select an option

Save thomasjm/6a2d60e3233fa55bc7765c2426784b33 to your computer and use it in GitHub Desktop.
Apple containers IP exhaustion test scripts
#!/bin/bash
# Test whether force-deleting containers leaks IP addresses.
# Creates containers and immediately force-deletes them in a loop.
# If IPs leak, we should hit "no free indices" around iteration ~252.
set -euo pipefail
IMAGE="docker.io/library/ubuntu:latest"
COUNT=0
FAILED=0
echo "Starting IP exhaustion test..."
echo "Subnet: $(container network inspect default 2>/dev/null | python3 -c "import sys,json; print(json.load(sys.stdin)[0]['status']['ipv4Subnet'])")"
echo ""
while true; do
COUNT=$((COUNT + 1))
NAME="ip-leak-test-${COUNT}"
# Create container
if ! OUTPUT=$(container run --name "$NAME" --detach "$IMAGE" sleep infinity 2>&1); then
echo "FAILED at iteration ${COUNT}: ${OUTPUT}"
FAILED=$((FAILED + 1))
if [ $FAILED -ge 3 ]; then
echo ""
echo "=== RESULT: IP exhaustion after ~${COUNT} iterations ==="
break
fi
continue
fi
# Grab the allocated IP
IP=$(container inspect "$NAME" 2>/dev/null \
| python3 -c "import sys,json; print(json.load(sys.stdin)[0]['networks'][0]['ipv4Address'])" 2>/dev/null || echo "unknown")
# Immediately force-delete (mimicking our current behavior)
container delete --force "$NAME" 2>/dev/null || true
echo " [${COUNT}] ${NAME} -> ${IP}"
if (( COUNT > 300 )); then
echo ""
echo "=== RESULT: No exhaustion after ${COUNT} iterations. IPs are being reclaimed. ==="
break
fi
done
# Cleanup any stragglers
for i in $(seq 1 $COUNT); do
container delete --force "ip-leak-test-${i}" 2>/dev/null || true
done
echo "Done."
#!/bin/bash
# Test whether gracefully stopping containers before deleting avoids IP leaks.
# Same as test_ip_exhaustion.sh but uses stop + delete instead of delete --force.
set -euo pipefail
IMAGE="docker.io/library/ubuntu:latest"
COUNT=0
FAILED=0
echo "Starting IP exhaustion test (graceful stop + delete)..."
echo "Subnet: $(container network inspect default 2>/dev/null | python3 -c "import sys,json; print(json.load(sys.stdin)[0]['status']['ipv4Subnet'])")"
echo ""
while true; do
COUNT=$((COUNT + 1))
NAME="ip-leak-test-${COUNT}"
# Create container
if ! OUTPUT=$(container run --name "$NAME" --detach "$IMAGE" sleep infinity 2>&1); then
echo "FAILED at iteration ${COUNT}: ${OUTPUT}"
FAILED=$((FAILED + 1))
if [ $FAILED -ge 3 ]; then
echo ""
echo "=== RESULT: IP exhaustion after ~${COUNT} iterations ==="
break
fi
continue
fi
# Grab the allocated IP
IP=$(container inspect "$NAME" 2>/dev/null \
| python3 -c "import sys,json; print(json.load(sys.stdin)[0]['networks'][0]['ipv4Address'])" 2>/dev/null || echo "unknown")
# Gracefully stop, wait for it to leave "stopping" state, then delete
container stop "$NAME" 2>/dev/null || true
for _ in $(seq 1 30); do
STATUS=$(container inspect "$NAME" 2>/dev/null \
| python3 -c "import sys,json; print(json.load(sys.stdin)[0].get('status','unknown'))" 2>/dev/null || echo "gone")
[ "$STATUS" != "stopping" ] && break
sleep 1
done
container delete "$NAME" 2>/dev/null || true
echo " [${COUNT}] ${NAME} -> ${IP}"
if (( COUNT > 300 )); then
echo ""
echo "=== RESULT: No exhaustion after ${COUNT} iterations. IPs are being reclaimed. ==="
break
fi
done
# Cleanup any stragglers
for i in $(seq 1 $COUNT); do
container stop "ip-leak-test-${i}" 2>/dev/null || true
container delete "ip-leak-test-${i}" 2>/dev/null || true
done
echo "Done."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment