import docker import requests import os import time 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) #input("Press Enter to continue with backup...") for v in vols: backup_volume(v) time.sleep(10) # Small delay to ensure stack is fully stopped start_stack(stack_name) # Backup normal volumes for v in normal_volumes: backup_volume(v) if __name__ == "__main__": main()