feat(docker): admin-gated per-host prune buttons on the image/disk page
M78 step 2. The /disk page surfaced reclaimable space + stopped counts but
said "prune deferred to a later milestone" — this wires the cleanup.
Adds POST /plugins/docker/disk/<host_id>/prune (admin only) that resolves
the host's linked AnsibleTarget → steward:target:<id> scope and fires the
bundled maintenance/docker_prune.yml through the ansible.run_playbook
capability (audited runner; the collection agent stays read-only). Mirrors
the host_agent update route. `target` ∈ {containers, images, system}:
- containers → docker container prune -f
- images → docker image prune -af (prune_all_images)
- system → docker system prune -f (conservative)
The disk() route now resolves each host group's linked target + capability
availability; disk.html renders three confirm-gated buttons per host, shown
only to admins when Ansible is available and the host has a linked target,
otherwise a clear "link a target" / "runner unavailable" hint (rules 24/26/27).
Tests: the prune_target→extra_vars mapping (the -af-only-for-images rule) is
extracted to a pure helper and unit-tested; disk_prune added to the module
smoke; disk.html covered by the existing template-parse test.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CAGR73DUowdVFVvYzLXC5C
This commit is contained in:
@@ -30,6 +30,22 @@ def test_routes_module_exposes_new_views():
|
||||
assert r.docker_bp.name == "docker"
|
||||
|
||||
|
||||
def test_disk_prune_view_defined():
|
||||
# M78 admin-gated prune action.
|
||||
assert callable(r.disk_prune)
|
||||
|
||||
|
||||
def test_prune_extra_vars_mapping():
|
||||
"""The prune buttons drive one playbook via prune_target; only 'images'
|
||||
widens to ALL unused images (docker image prune -a), system stays -f."""
|
||||
assert r._prune_extra_vars("containers") == {"prune_target": "containers"}
|
||||
assert r._prune_extra_vars("images") == {
|
||||
"prune_target": "images", "prune_all_images": True,
|
||||
}
|
||||
# System prune stays conservative — no prune_all_images key.
|
||||
assert r._prune_extra_vars("system") == {"prune_target": "system"}
|
||||
|
||||
|
||||
def test_human_bytes_formats_binary_units():
|
||||
assert r._human_bytes(None) == "—"
|
||||
assert r._human_bytes(0) == "0 B"
|
||||
|
||||
Reference in New Issue
Block a user