Files
Reset_Docker/docker_full_factory_reset.py
2026-09-13 19:54:18 +01:00

407 lines
12 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""
Docker Factory Reset Script for Ubuntu
Completely resets Docker to a fresh installation state.
"""
import subprocess
import sys
import os
import time
from typing import List
class ProgressBar:
"""Simple progress indicator for operations."""
def __init__(self, total: int, description: str = ""):
self.total = total
self.current = 0
self.description = description
def update(self, increment: int = 1):
self.current += increment
self._display()
def _display(self):
if self.total == 0:
percentage = 100
else:
percentage = int((self.current / self.total) * 100)
bar_length = 40
filled = int((percentage / 100) * bar_length)
bar = '█' * filled + '░' * (bar_length - filled)
print(f"\r [{bar}] {percentage}% ({self.current}/{self.total}) {self.description}", end='', flush=True)
def complete(self):
self.current = self.total
self._display()
print() # New line after completion
def run_cmd_realtime(cmd: List[str], check: bool = False, show_output: bool = True) -> int:
"""
Run a command and stream stdout/stderr in real-time.
Returns the exit code.
If check=True, exits the script on non-zero return code.
"""
if show_output:
print(f"\n▶ RUN: {' '.join(cmd)}")
print("─" * 60)
try:
process = subprocess.Popen(
cmd,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT, # Merge stderr into stdout
text=True,
bufsize=1, # Line buffered
)
# Stream output line by line
if show_output:
for line in process.stdout:
print(line, end='') # Print without adding extra newline
else:
# Consume output even if not showing
for _line in process.stdout:
pass
process.wait()
code = process.returncode
if show_output:
if code != 0:
print(f"✗ Command exited with code {code}")
if check:
sys.exit(code)
else:
print(f"✓ Command completed successfully")
return code
except FileNotFoundError:
print(f"✗ ERROR: Command not found: {' '.join(cmd)}")
sys.exit(1)
def run_cmd_quiet(cmd: List[str]) -> tuple:
"""
Run a command quietly and return (exit_code, stdout, stderr).
Used for listing/checking operations.
"""
try:
result = subprocess.run(
cmd,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
)
return result.returncode, result.stdout.strip(), result.stderr.strip()
except FileNotFoundError:
print(f"✗ ERROR: Command not found: {' '.join(cmd)}")
sys.exit(1)
def require_root():
if os.geteuid() != 0:
print("✗ This script must be run as root (use sudo).")
sys.exit(1)
def docker_installed() -> bool:
code, out, err = run_cmd_quiet(["docker", "--version"])
if code != 0:
print("✗ Docker does not appear to be installed or accessible.")
if err:
print(err)
return False
print(f"✓ Docker found: {out}")
return True
def list_ids(cmd: List[str]) -> List[str]:
code, out, _err = run_cmd_quiet(cmd)
if code != 0:
return []
return [line.strip() for line in out.splitlines() if line.strip()]
def stop_and_remove_containers():
print("\n" + "=" * 60)
print("STEP 1/8: CONTAINERS")
print("=" * 60)
container_ids = list_ids(["docker", "ps", "-aq"])
if not container_ids:
print(" No containers found.")
return
print(f" Found {len(container_ids)} container(s)")
running_ids = list_ids(["docker", "ps", "-q"])
if running_ids:
print(f"\n Stopping {len(running_ids)} running container(s)...")
progress = ProgressBar(len(running_ids), "stopping containers")
for container_id in running_ids:
run_cmd_realtime(["docker", "stop", container_id], show_output=False)
progress.update()
progress.complete()
else:
print(" No running containers to stop.")
print(f"\n Removing all {len(container_ids)} container(s)...")
progress = ProgressBar(len(container_ids), "removing containers")
for container_id in container_ids:
run_cmd_realtime(["docker", "rm", "-f", container_id], show_output=False)
progress.update()
progress.complete()
print("✓ All containers removed")
def remove_images():
print("\n" + "=" * 60)
print("STEP 2/8: IMAGES")
print("=" * 60)
image_ids = list_ids(["docker", "images", "-aq"])
if not image_ids:
print(" No images found.")
return
print(f" Found {len(image_ids)} image(s)")
print("\n Removing all images...")
progress = ProgressBar(len(image_ids), "removing images")
for image_id in image_ids:
run_cmd_realtime(["docker", "rmi", "-f", image_id], show_output=False)
progress.update()
progress.complete()
print("✓ All images removed")
def remove_networks():
print("\n" + "=" * 60)
print("STEP 3/8: NETWORKS")
print("=" * 60)
code, out, err = run_cmd_quiet(["docker", "network", "ls", "--format", "{{.Name}}"])
if code != 0:
print(f"✗ Error listing networks: {err}")
return
default_networks = {"bridge", "host", "none"}
networks = [n.strip() for n in out.splitlines() if n.strip()]
custom_networks = [n for n in networks if n not in default_networks]
if not custom_networks:
print(" No custom networks found.")
return
print(f" Found {len(custom_networks)} custom network(s): {', '.join(custom_networks)}")
print("\n Removing custom networks...")
progress = ProgressBar(len(custom_networks), "removing networks")
for network in custom_networks:
run_cmd_realtime(["docker", "network", "rm", network], show_output=False)
progress.update()
progress.complete()
print("✓ All custom networks removed")
def remove_volumes():
print("\n" + "=" * 60)
print("STEP 4/8: VOLUMES")
print("=" * 60)
volume_names = list_ids(["docker", "volume", "ls", "-q"])
if not volume_names:
print(" No volumes found.")
return
print(f" Found {len(volume_names)} volume(s)")
print("\n Removing all volumes...")
progress = ProgressBar(len(volume_names), "removing volumes")
for volume in volume_names:
run_cmd_realtime(["docker", "volume", "rm", "-f", volume], show_output=False)
progress.update()
progress.complete()
print("✓ All volumes removed")
def prune_system():
print("\n" + "=" * 60)
print("STEP 5/8: SYSTEM PRUNE & BUILD CACHE")
print("=" * 60)
print(" Pruning builder cache...")
run_cmd_realtime(["docker", "builder", "prune", "-af"])
print("\n Running system prune (extra safety)...")
run_cmd_realtime(["docker", "system", "prune", "-af", "--volumes"])
def stop_docker_service():
print("\n" + "=" * 60)
print("STEP 6/8: STOP DOCKER DAEMON")
print("=" * 60)
print(" Stopping Docker service...")
run_cmd_realtime(["systemctl", "stop", "docker"])
print("\n Stopping containerd service...")
run_cmd_realtime(["systemctl", "stop", "containerd"])
print("✓ Docker daemon stopped")
def wipe_docker_data_dirs():
print("\n" + "=" * 60)
print("STEP 7/8: DELETE DOCKER DATA DIRECTORIES")
print("=" * 60)
paths = ["/var/lib/docker", "/var/lib/containerd"]
existing_paths = [p for p in paths if os.path.exists(p)]
if not existing_paths:
print(" No Docker data directories found.")
return
print(f" Found {len(existing_paths)} data director(ies) to delete")
progress = ProgressBar(len(existing_paths), "deleting directories")
for p in paths:
if os.path.exists(p):
print(f"\n Deleting {p} ...")
code, out, _err = run_cmd_quiet(["du", "-sh", p])
if code == 0 and out:
print(f" Size: {out.split()[0]}")
run_cmd_realtime(["rm", "-rf", p], show_output=False)
progress.update()
else:
print(f" {p} does not exist; skipping.")
progress.complete()
print("✓ All Docker data directories deleted")
def start_docker_service():
print("\n" + "=" * 60)
print("STEP 8/8: START DOCKER DAEMON")
print("=" * 60)
print(" Starting containerd service...")
run_cmd_realtime(["systemctl", "start", "containerd"])
print("\n Starting Docker service...")
run_cmd_realtime(["systemctl", "start", "docker"])
print("\n Waiting for Docker to initialize...")
for i in range(5):
time.sleep(1)
code, out, _err = run_cmd_quiet(["systemctl", "is-active", "docker"])
if code == 0 and out.strip() == "active":
print(f"✓ Docker service is active (took {i+1}s)")
break
else:
print("⚠ Warning: Docker service may not be active yet.")
print("\n Running docker info to verify...")
run_cmd_realtime(["docker", "info"])
def show_final_state():
print("\n" + "=" * 60)
print("FINAL DOCKER STATE")
print("=" * 60)
cmds = [
(["docker", "ps", "-a"], "CONTAINERS"),
(["docker", "images"], "IMAGES"),
(["docker", "network", "ls"], "NETWORKS"),
(["docker", "volume", "ls"], "VOLUMES"),
]
for cmd, title in cmds:
print(f"\n{title}")
print("─" * 60)
code, out, err = run_cmd_quiet(cmd)
if code == 0:
print(out if out else "(empty)")
else:
print("✗ Command failed")
if err:
print(err)
def show_banner():
banner = """
╔════════════════════════════════════════════════════════════╗
║ ║
║ DOCKER FACTORY RESET FOR UBUNTU ║
║ ║
║ Completely resets Docker to fresh state ║
║ ║
╚════════════════════════════════════════════════════════════╝
"""
print(banner)
def main():
show_banner()
require_root()
if not docker_installed():
sys.exit(1)
print("\n⚠ WARNING: This script will COMPLETELY RESET Docker on this Ubuntu host.")
print("\nIt will:")
print(" • Stop and remove ALL containers (running and stopped)")
print(" • Remove ALL images")
print(" • Remove ALL volumes")
print(" • Remove ALL custom networks")
print(" • Prune ALL build cache and system data")
print(" • STOP Docker daemon")
print(" • DELETE /var/lib/docker and /var/lib/containerd")
print(" • START Docker daemon again")
print("\n⚠ You will lose ALL Docker data on this machine.")
print("\n" + "─" * 60)
confirm = input("\nType 'RESET_DOCKER_UBUNTU' to continue: ")
if confirm != "RESET_DOCKER_UBUNTU":
print("\n✗ Aborted.")
sys.exit(0)
start_time = time.time()
stop_and_remove_containers()
remove_images()
remove_networks()
remove_volumes()
prune_system()
stop_docker_service()
wipe_docker_data_dirs()
start_docker_service()
show_final_state()
elapsed_time = time.time() - start_time
print("\n" + "=" * 60)
print("✓ DOCKER FACTORY RESET COMPLETE")
print(f" Total time: {elapsed_time:.2f} seconds")
print("=" * 60)
print("\nDocker has been reset to a fresh installation state.\n")
if __name__ == "__main__":
main()