computer-playbook/roles/storage-optimizer/files/storage-optimizer.py

88 lines
3.1 KiB
Python
Raw Normal View History

2024-01-09 12:47:00 +01:00
import subprocess
import os
import shutil
2024-01-09 18:31:44 +01:00
import argparse
2024-01-09 12:47:00 +01:00
def run_command(command):
""" Run a shell command and return its output """
return subprocess.check_output(command, shell=True).decode('utf-8').strip()
2024-01-09 14:20:30 +01:00
def stop_containers(containers):
"""Stop a list of containers."""
container_list = ' '.join(containers)
print(f"Stopping containers {container_list}...")
2024-01-09 18:31:44 +01:00
run_command(f"docker stop {container_list}")
2024-01-09 14:20:30 +01:00
def start_containers(containers):
"""Start a list of containers."""
container_list = ' '.join(containers)
2024-01-09 18:31:44 +01:00
print(f"Starting containers {container_list}...")
run_command(f"docker start {container_list}")
2024-01-09 14:20:30 +01:00
def is_database(image):
2024-01-09 18:44:52 +01:00
databases = {"postgres", "mariadb", "redis", "memcached"}
return any(database in image for database in databases)
2024-01-09 14:20:30 +01:00
def is_symbolic_link(file_path):
return os.path.islink(file_path)
def get_volume_path(volume):
return run_command(f"docker volume inspect --format '{{{{ .Mountpoint }}}}' {volume}")
2024-01-09 18:31:44 +01:00
def get_image(container):
2024-01-09 14:20:30 +01:00
return run_command(f"docker inspect --format='{{{{.Config.Image}}}}' {container}")
2024-01-09 18:31:44 +01:00
def pause_and_move(storage_path, volume, volume_path, containers):
2024-01-09 14:20:30 +01:00
stop_containers(containers)
# Create a new directory on the Storage
2024-01-10 12:19:19 +01:00
storage_volume_path = os.path.join(storage_path, 'data', 'docker', 'volumes', volume)
2024-01-09 14:20:30 +01:00
os.makedirs(storage_volume_path, exist_ok=False)
# Move the data
for item in os.listdir(volume_path):
shutil.move(os.path.join(volume_path, item), storage_volume_path)
# Create a symbolic link
os.symlink(storage_volume_path, volume_path)
start_containers(containers)
2024-01-09 18:44:52 +01:00
def has_container_with_database(containers):
for container in containers:
# Get the image of the container
image = get_image(container)
if is_database(image):
return True
return False
if __name__ == "__main__":
# Argument parser setup
parser = argparse.ArgumentParser(description='Migrate Docker volumes to SSD or HDD based on container image.')
2024-01-10 10:33:39 +01:00
parser.add_argument('--rapid-storage-path', type=str, required=True, help='Path to the SSD storage')
parser.add_argument('--mass-storage-path', type=str, required=True, help='Path to the HDD storage')
2024-01-09 14:20:30 +01:00
# Parse arguments
args = parser.parse_args()
2024-01-09 12:47:00 +01:00
# Set paths from arguments
2024-01-10 10:33:39 +01:00
rapid_storage_path = args.rapid_storage_path
mass_storage_path = args.mass_storage_path
2024-01-09 12:47:00 +01:00
# List all Docker volumes
volumes = run_command("docker volume ls -q").splitlines()
for volume in volumes:
containers = run_command(f"docker ps -q --filter volume={volume}").splitlines()
volume_path = get_volume_path(volume)
if is_symbolic_link(volume_path):
print(f"Skipped Volume {volume}. The storage path {volume_path} is a symbolic link.")
2024-01-09 18:44:52 +01:00
elif has_container_with_database(containers):
2024-01-09 18:49:46 +01:00
print(f"Safing volume {volume} on SSD.")
2024-01-10 10:33:39 +01:00
pause_and_move(rapid_storage_path, volume, volume_path, containers)
2024-01-09 18:44:52 +01:00
else:
2024-01-09 18:49:46 +01:00
print(f"Safing volume {volume} on HDD.")
2024-01-10 10:33:39 +01:00
pause_and_move(mass_storage_path, volume, volume_path, containers)
2024-01-09 18:49:46 +01:00
print("Operation completed.")