Commit Graph
4 Commits
Author SHA1 Message Date
menzeljandClaude Opus 5 ee98d0da6d Show live progress while pruning networks, and ask first (0.63.0)
CI / check (push) Successful in 13m10s
CI / build-and-push (push) Successful in 1m57s
The network prune joins the image and volume prunes on the shared
PruneJob: it runs in the background, the Networks page shows a progress
bar and a toast with the outcome, and the button now asks before deleting
instead of pruning on click. Docker has no -a for networks and they hold
no data, so there is no option and no space figure.

Candidates are stricter than docker network prune, which goes by active
endpoints and so removes a stopped container's network, after which that
container fails to start ("network not found"). A network any container,
running or stopped, is attached to (by name or id) is kept, as are
bridge/host/none, ingress/docker_gwbridge and swarm-scoped networks.
Removal is per network, so one the daemon refuses does not stop the rest.

- POST /api/networks/prune takes background=; without it it still waits
  and returns {NetworksDeleted}. GET /api/networks/prune-status is
  admin-only and registered before /{network_id}, which would otherwise
  take "prune-status" for an id.
- The long-timeout test for network prune in test_docker_timeouts.py is
  superseded by test_network_prune.py.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-18 10:49:29 +02:00
menzeljandClaude Opus 5 57231e4a67 Show live progress while pruning volumes, and ask first (0.62.0)
CI / check (push) Successful in 13m19s
CI / build-and-push (push) Successful in 1m57s
The volume prune gets the same treatment as the image prune in 0.61.0:
the candidates are listed and removed one by one in the background, and
the Volumes page shows a progress bar (x / y, the volume being removed,
failures) followed by a toast with the space freed.

The button also used to delete without asking, and a bare docker volume
prune only removes anonymous volumes on Engine 23+ with no way to include
named ones. It now opens a confirmation dialog with an explicit -a option
that warns it also takes the data of every stack that is down.

- Candidates: volumes no container (running or stopped) mounts, local
  scope only, and anonymous (com.docker.volume.anonymous) unless -a.
  Volumes from pre-23 daemons carry no such label, so they only go with
  -a, which errs on the side of keeping data.
- Removed without force, so a volume mounted since the listing is
  refused; one refusal does not stop the rest.
- No closing daemon prune: nothing is left over, and on a pre-23 daemon an
  unfiltered one would delete named volumes too.
- Freed space is the sum of the deleted volumes' sizes (volumes share no
  data), from the size cache, which is invalidated afterwards.
- POST /api/volumes/prune takes all= and background=; without background
  it still waits and returns {VolumesDeleted, SpaceReclaimed}.
  GET /api/volumes/prune-status is admin-only.
- volume_sizes() ("Compute sizes") now uses the long-timeout client; it
  walks every volume and could hit the same 60s limit.

The progress machinery moved into services/prune_job.py (PruneJob,
PrunePlan) and, on the frontend, the usePruneJob hook and PruneProgress
component, shared by both pages. The status now carries a phase
(preparing / removing / finishing) so the parts without a count say what
they are doing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-18 10:23:51 +02:00
menzeljandClaude Opus 5 faff2be944 Show live progress while pruning images (0.61.0)
CI / check (push) Successful in 13m53s
CI / build-and-push (push) Successful in 1m58s
docker image prune is a single blocking call that reports nothing until it
is done. With -a on a host with many images that meant minutes of a
spinner, and past the proxy timeout an error while the daemon carried on.

The prune now removes its candidates one by one and publishes how far it
is. The candidates are the ones Docker would pick: dangling only by
default, with -a every image no container (running or stopped) uses. The
UI starts the prune in the background (POST /api/images/prune?background=
true, 202) and polls GET /api/images/prune-status. A progress bar above
the image table shows x / y, the image being removed and any failures,
and a toast reports the outcome. It survives a reload and shows up in a
second tab.

- Multi-tag images lose their tags one by one instead of force=True, so a
  container created since the listing still makes the daemon refuse.
- One refused image does not stop the rest; up to ten errors are kept.
- Docker's own prune runs last to sweep up leftovers.
- Freed space is measured (image LayersSize before and after) rather than
  summed, which would count base layers shared with the images that stay.
- Without background=true the endpoint still waits and returns the old
  {ImagesDeleted, SpaceReclaimed} shape, so API-token scripts are
  unaffected. A second prune while one runs gets 409.
- The audit entry now counts deleted images, not Docker's untag entries.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-18 10:15:14 +02:00
menzeljandClaude Opus 5 f766ded528 Stop long prunes failing with a bare 500 (0.60.1)
CI / check (push) Successful in 13m35s
CI / build-and-push (push) Successful in 2m10s
A prune that deletes a lot of data (image prune -a in particular) easily
runs past docker-py's 60s read timeout. requests' ReadTimeout is not a
DockerException, so it slipped past safe_call and the UI only showed
"Request failed with status code 500".

Prunes now use a client with a 540s timeout (below nginx's 600s
proxy_read_timeout), and safe_call turns transport timeouts and
connection errors into DockerError, so they surface as a 502 with a
message.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-18 09:39:47 +02:00