Files
hermes-recovery/scripts/snapshot-hetzner.py
T

61 lines
1.8 KiB
Python
Executable File

#!/usr/bin/env python3
"""Create a snapshot of ALL running servers in the Hetzner account."""
import urllib.request, json, os, sys, time
API = "https://api.hetzner.cloud/v1"
# Read token from file to avoid shell issues
script_dir = os.path.dirname(os.path.abspath(__file__))
token_file = os.path.join(script_dir, ".hetzner_token")
try:
with open(token_file) as f:
TOKEN = f.read().strip()
except FileNotFoundError:
print(f"HETZNER_TOKEN file not found at {token_file}")
sys.exit(1)
HEADERS = {"Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json"}
def api(path, data=None, method=None):
req = urllib.request.Request(f"{API}/{path}", headers=HEADERS, method=method)
if data:
req.data = json.dumps(data).encode()
try:
resp = urllib.request.urlopen(req)
return json.loads(resp.read()) if resp.status != 204 else {}
except urllib.error.HTTPError as e:
body = e.read().decode()
print(f" ERROR {e.code}: {body}")
return None
# Get all servers
servers = api("servers") or {"servers": []}
if not servers["servers"]:
print("No servers found.")
sys.exit(0)
print(f"Found {len(servers['servers'])} servers\n")
for s in servers["servers"]:
name = s["name"]
sid = s["id"]
status = s["status"]
if status != "running":
print(f" SKIP {name:30s}{status}")
continue
print(f" SNAPSHOT {name:30s} (ID: {sid}) ...", end=" ", flush=True)
result = api(f"servers/{sid}/actions/create_image", {
"type": "snapshot",
"description": f"auto-weekly-{name}-{time.strftime('%Y-%m-%d')}"
}, method="POST")
if result:
action = result.get("action", {})
print(f"started (action {action.get('id', '?')})")
else:
print("FAILED")
print("\nDone.")