61 lines
1.8 KiB
Python
Executable File
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.")
|