Files
docker-compose/backup_volumes.py
2025-11-30 19:35:08 +01:00

90 lines
2.7 KiB
Python

import docker
import requests
import os
PORTAINER_URL = "https://port.sectorq.eu/api"
API_KEY = "ptr_/5RkMCT/j3BTaL32vMSDtXFi76yOXRKVFOrUtzMsl5Y="
HEADERS = {"X-API-Key": f"{API_KEY}"}
ENDPOINT_ID = 4
client = docker.from_env()
# Keep track of which stacks we already stopped
stopped_stacks = {}
def get_stack_by_name(stack_name):
url = f"{PORTAINER_URL}/stacks"
r = requests.get(url, headers=HEADERS)
r.raise_for_status()
for s in r.json():
if s['Name'] == stack_name:
return s
return None
def stop_stack(stack_name):
if stack_name in stopped_stacks:
return
stack = get_stack_by_name(stack_name)
if not stack:
print(f"[INFO] Stack {stack_name} not found, skipping stop")
return
url = f"{PORTAINER_URL}/stacks/{stack['Id']}/stop?endpointId={ENDPOINT_ID}"
print(f"url: {url}")
r = requests.post(url, headers=HEADERS)
if r.status_code == 200:
print(f"[OK] Stack {stack_name} stopped")
else:
print(f"[ERROR] Failed to stop stack {stack_name}: {r.text}")
stopped_stacks[stack_name] = True
def start_stack(stack_name):
stack = get_stack_by_name(stack_name)
if not stack:
print(f"[INFO] Stack {stack_name} not found, skipping start")
return
url = f"{PORTAINER_URL}/stacks/{stack['Id']}/start?endpointId={ENDPOINT_ID}"
r = requests.post(url, headers=HEADERS)
if r.status_code == 200:
print(f"[OK] Stack {stack_name} started")
else:
print(f"[ERROR] Failed to start stack {stack_name}: {r.text}")
def backup_volume(vol):
vol_name = vol.name
backup_file = f"/backup/{vol_name}.tar"
print(f"[INFO] Backing up volume {vol_name}{backup_file}")
# Use a temporary container to archive the volume
client.containers.run(
image="alpine",
command=f"tar czf /backup/{vol_name}.tar -C /data .",
volumes={vol_name: {'bind': '/data', 'mode': 'ro'},
"/backup": {'bind': '/backup', 'mode': 'rw'}},
remove=True
)
def main():
volumes = client.volumes.list()
stack_volumes = {}
normal_volumes = []
# Categorize volumes by stack
for vol in volumes:
labels = vol.attrs.get('Labels', {})
stack_name = labels.get('com.docker.stack.namespace')
if stack_name:
stack_volumes.setdefault(stack_name, []).append(vol)
else:
normal_volumes.append(vol)
# Backup stacks
for stack_name, vols in stack_volumes.items():
stop_stack(stack_name)
for v in vols:
backup_volume(v)
start_stack(stack_name)
# Backup normal volumes
for v in normal_volumes:
backup_volume(v)
if __name__ == "__main__":
main()