Create main.py
This commit is contained in:
committed by
GitHub
parent
8f284bd939
commit
10a0a7dea5
118
main.py
Normal file
118
main.py
Normal file
@@ -0,0 +1,118 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import subprocess
|
||||
import re
|
||||
import sys
|
||||
import os
|
||||
from pathlib import Path
|
||||
import shutil
|
||||
|
||||
VOLUME_BASE_PATH = Path("/var/lib/docker/volumes")
|
||||
|
||||
def get_anonymous_volumes():
|
||||
result = subprocess.run(
|
||||
["docker", "volume", "ls", "--format", "{{.Name}}"],
|
||||
stdout=subprocess.PIPE,
|
||||
text=True
|
||||
)
|
||||
return [
|
||||
vol for vol in result.stdout.splitlines()
|
||||
if re.fullmatch(r"[a-f0-9]{64}", vol)
|
||||
]
|
||||
|
||||
def get_mount_path(volume):
|
||||
containers = subprocess.run(["docker", "ps", "-q"], stdout=subprocess.PIPE, text=True).stdout.split()
|
||||
for container_id in containers:
|
||||
mount_path = subprocess.run(
|
||||
[
|
||||
"docker", "inspect", container_id,
|
||||
"--format", f"{{{{range .Mounts}}}}{{{{if eq .Name \"{volume}\"}}}}{{{{.Destination}}}}{{{{end}}}}{{{{end}}}}"
|
||||
],
|
||||
stdout=subprocess.PIPE,
|
||||
text=True
|
||||
).stdout.strip()
|
||||
if mount_path:
|
||||
return mount_path
|
||||
return None
|
||||
|
||||
def is_volume_used(volume):
|
||||
result = subprocess.run(
|
||||
["docker", "ps", "-aq", "--filter", f"volume={volume}"],
|
||||
stdout=subprocess.PIPE,
|
||||
text=True
|
||||
)
|
||||
return bool(result.stdout.strip())
|
||||
|
||||
def cleanup_symlink(volume):
|
||||
volume_path = VOLUME_BASE_PATH / volume
|
||||
if volume_path.is_symlink():
|
||||
target_path = volume_path.resolve()
|
||||
print(f"Volume directory {volume_path} is a symlink to {target_path}.")
|
||||
try:
|
||||
print(f"Removing symlink: {volume_path}")
|
||||
volume_path.unlink()
|
||||
if target_path.exists():
|
||||
print(f"Removing symlink target directory: {target_path}")
|
||||
shutil.rmtree(target_path)
|
||||
except Exception as e:
|
||||
print(f"Failed to clean up symlink or target for {volume}: {e}")
|
||||
|
||||
def delete_volume(volume):
|
||||
cleanup_symlink(volume)
|
||||
subprocess.run(["docker", "volume", "rm", volume])
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Remove unused anonymous Docker volumes.")
|
||||
parser.add_argument("whitelist", nargs="?", default="", help="Space-separated list of whitelisted volume IDs")
|
||||
parser.add_argument("--no-confirmation", action="store_true", help="Skip confirmation before deleting volumes")
|
||||
args = parser.parse_args()
|
||||
|
||||
whitelist = set(args.whitelist.split())
|
||||
|
||||
anonymous_volumes = get_anonymous_volumes()
|
||||
if not anonymous_volumes:
|
||||
print("No anonymous volumes found.")
|
||||
sys.exit(0)
|
||||
|
||||
to_delete = []
|
||||
|
||||
print("Checking anonymous volumes...\n")
|
||||
|
||||
for volume in anonymous_volumes:
|
||||
if volume in whitelist:
|
||||
print(f"Volume {volume} is whitelisted and will be skipped.")
|
||||
continue
|
||||
|
||||
mount_path = get_mount_path(volume)
|
||||
if mount_path == "/var/www/bootstrap":
|
||||
print(f"Volume {volume} is mounted at /var/www/bootstrap and will be skipped.")
|
||||
continue
|
||||
|
||||
if not is_volume_used(volume):
|
||||
print(f"Volume {volume} is not used by any running containers.")
|
||||
to_delete.append(volume)
|
||||
else:
|
||||
print(f"Volume {volume} is still used and will not be deleted.")
|
||||
|
||||
if not to_delete:
|
||||
print("\nNo unused anonymous volumes to delete.")
|
||||
sys.exit(0)
|
||||
|
||||
print("\nThe following volumes will be deleted:")
|
||||
for vol in to_delete:
|
||||
print(f" - {vol}")
|
||||
|
||||
if not args.no_confirmation:
|
||||
confirm = input("\nDo you want to proceed? [y/N]: ").lower()
|
||||
if confirm != "y":
|
||||
print("Aborted.")
|
||||
sys.exit(1)
|
||||
|
||||
for volume in to_delete:
|
||||
delete_volume(volume)
|
||||
|
||||
print("\nUnused anonymous volumes deleted.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user