Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,16 @@ All notable changes to the Lager platform are documented here. For detailed rele
server's rotation replay detection). Found by the box-lifecycle CI's
first supervised runs.

- **`lager install` and `lager uninstall` no longer remove containers and
images they do not own.** The deploy script stopped and force-removed
EVERY container on the box and pruned every unused image; uninstall's
image cleanup did the same prune. On a box that also runs third-party
containers (a management agent, a user's own services) this destroyed
infrastructure the tooling cannot restore. Cleanup is now scoped to the
containers lager creates (`lager`, `pigpio`, legacy `controller`), the
lager image, and dangling layers. Found by the box-lifecycle CI's first
supervised reinstall, which took down the box's gateway agent.

## [0.32.3] - 2026-07-22

### Fixed
Expand Down
11 changes: 8 additions & 3 deletions cli/commands/utility/uninstall.py
Original file line number Diff line number Diff line change
Expand Up @@ -603,7 +603,7 @@ def query_ssh(cmd):
click.echo(" - Docker containers (lager, pigpio)")
click.echo(" - Docker network (lagernet)")
if not keep_docker_images:
click.echo(" - Docker images (ALL unused images on the box, not only lager's)")
click.echo(" - Docker images (the lager image and dangling layers only)")
click.echo(" - ~/box directory")
if not keep_config:
click.echo(" - /etc/lager directory (saved nets)")
Expand Down Expand Up @@ -707,10 +707,15 @@ def run_priv_session(steps):
run_ssh("docker network rm lagernet 2>/dev/null", "Removing lagernet network", allow_fail=True)
click.echo()

# Remove Docker images (unless --keep-docker-images)
# Remove Docker images (unless --keep-docker-images). Scoped to the
# lager image plus dangling layers: 'prune -af' would also delete
# images belonging to any OTHER stopped container on the box (a
# management agent, a user's own services) — infrastructure this
# command cannot restore.
click.secho("[Step 2/5] Cleaning Docker...", fg='cyan')
if not keep_docker_images:
run_ssh("docker image prune -af 2>/dev/null", "Removing Docker images", allow_fail=True)
run_ssh("docker rmi -f lager 2>/dev/null", "Removing lager image", allow_fail=True)
run_ssh("docker image prune -f 2>/dev/null", "Removing dangling images", allow_fail=True)
run_ssh("docker builder prune -af 2>/dev/null", "Clearing Docker build cache", allow_fail=True)
else:
click.echo(" Skipping Docker image removal (--keep-docker-images)")
Expand Down
34 changes: 19 additions & 15 deletions cli/deployment/scripts/setup_and_deploy_box.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1339,33 +1339,37 @@ print_info "Ensuring Docker service is enabled (for auto-start on boot)..."
ssh $SSH_OPTS "${BOX_USER}@${BOX_IP}" "sudo systemctl enable docker >/dev/null 2>&1 || true"
print_success "Docker service enabled"

print_info "Stopping and removing all existing containers..."
# Update restart policy first to prevent auto-restart, then force remove all containers
print_info "Stopping and removing lager containers..."
# Scoped to the containers this deployment owns (lager, pigpio, and the
# legacy controller). A box may run third-party containers alongside lager
# — a management agent, a user's own services — and removing containers we
# did not create takes down infrastructure this script cannot restore.
# Update restart policy first to prevent auto-restart, then force remove.
ssh $SSH_OPTS "${BOX_USER}@${BOX_IP}" "
# Disable auto-restart on all containers first
docker update --restart=no \$(docker ps -aq) 2>/dev/null || true
# Stop all running containers
docker stop \$(docker ps -q) 2>/dev/null || true
# Remove all containers (running and stopped)
docker rm -f \$(docker ps -aq) 2>/dev/null || true
# Prune any leftover containers
docker container prune -f 2>/dev/null || true
for c in lager pigpio controller; do
docker update --restart=no \$c 2>/dev/null || true
docker stop \$c 2>/dev/null || true
docker rm -f \$c 2>/dev/null || true
done
# Wait a moment for Docker to clean up
sleep 2
" 2>/dev/null || true
print_success "All containers cleaned up"
print_success "Lager containers cleaned up"

print_info "Cleaning up Docker images and build cache to free disk space..."
print_info "Cleaning up Docker build cache and dangling images..."
echo ""
# Dangling-only (no -a): 'prune -af' would also delete images belonging to
# third-party containers stopped at this moment, which cannot be re-pulled
# by this script.
ssh $SSH_OPTS "${BOX_USER}@${BOX_IP}" "
echo 'Removing unused Docker images...'
docker image prune -af 2>/dev/null || true
echo 'Removing dangling Docker images...'
docker image prune -f 2>/dev/null || true
echo 'Removing Docker build cache...'
docker builder prune -af 2>/dev/null || true
echo 'Cleanup complete'
" 2>/dev/null || true
echo ""
print_success "Docker images and build cache cleaned up"
print_success "Docker build cache and dangling images cleaned up"

print_info "Checking available disk space..."
ssh $SSH_OPTS "${BOX_USER}@${BOX_IP}" "df -h / | tail -n 1 | awk '{print \"Available: \" \$4 \" (\" \$5 \" used)\"}'" 2>/dev/null || true
Expand Down
Loading