#!/usr/bin/env python3 """Attrappe von `rbd` - lesende Auskuenfte fuer Bildschirmfotos und Tests. Die Kulisse enthaelt bewusst beide Zustaende, um die es beim Aufraeumen geht: vm-101-disk-0@auto-stuendlich-20260809-100000 geschuetzt, MIT Klon -> muss in Ruhe gelassen werden vm-105-disk-0@auto-taeglich-20260809-023000 geschuetzt, OHNE Klon -> genau der Fall, den find_stale_protections sucht vm-100-disk-0@auto-taeglich-20260809-023000 ungeschuetzt -> geht niemanden etwas an """ import json import sys # Abbild -> Elternteil (nur Klone haben einen) ELTERN = { "vm-9101-disk-0": "vmdaten/vm-101-disk-0@auto-stuendlich-20260809-100000", } # Abbild -> [(Snapshot, geschuetzt?)] SNAPSHOTS = { "vm-100-disk-0": [("auto-taeglich-20260809-023000", False)], "vm-101-disk-0": [("auto-taeglich-20260809-023000", False), ("auto-stuendlich-20260809-100000", True)], "vm-105-disk-0": [("auto-taeglich-20260809-023000", True), ("golden", False)], } POOLS = { "vmdaten": ["vm-100-disk-0", "vm-101-disk-0", "vm-102-disk-0", "vm-105-disk-0", "vm-130-disk-0", "vm-9101-disk-0", "vm-9102-disk-0"], "ctdaten": ["subvol-110-disk-0", "subvol-111-disk-0"], } GROESSEN = {"vm-101-disk-0": 400, "vm-105-disk-0": 250, "vm-9101-disk-0": 400} # Optionen, hinter denen noch ein Wert steht - sonst haelt man "-m " # fuer den Befehl. MIT_WERT = {"-m", "--id", "--keyring", "-c", "--conf", "-p", "--pool", "--namespace", "-n", "--name", "--snap", "--format"} def zerlege(argv): """(Woerter ohne Optionen, {Option: Wert}) aus der Kommandozeile.""" rest, optionen = [], {} index = 0 while index < len(argv): wort = argv[index] if wort in MIT_WERT: optionen[wort] = argv[index + 1] if index + 1 < len(argv) else "" index += 2 continue if wort.startswith("-"): optionen[wort] = True index += 1 continue rest.append(wort) index += 1 return rest, optionen def teile(ziel): """pool/abbild@snap -> (abbild, snap)""" ohne_pool = ziel.split("/")[-1] abbild, _, snap = ohne_pool.partition("@") return abbild, snap def kinder(abbild, snap): return [k for k, eltern in ELTERN.items() if eltern.endswith("/%s@%s" % (abbild, snap))] def main(argv): rest, optionen = zerlege(argv) if not rest: return 1 befehl = rest[0] ziel = rest[1] if len(rest) > 1 else "" abbild, snap = teile(ziel) if befehl == "ls": for name in POOLS.get(ziel or "vmdaten", []): print(name) return 0 if befehl == "info": eltern = ELTERN.get(abbild) gigabyte = GROESSEN.get(abbild, 32) if optionen.get("--format") == "json": daten = {"name": abbild, "size": gigabyte * 1024 ** 3, "format": 2, "snapshot_count": len(SNAPSHOTS.get(abbild, []))} if eltern: pool, _, rest_ = eltern.partition("/") bild, _, s = rest_.partition("@") daten["parent"] = {"pool": pool, "image": bild, "snapshot": s} print(json.dumps(daten)) return 0 print("rbd image '%s':" % abbild) print("\tsize %d GiB in %d objects" % (gigabyte, gigabyte * 256)) print("\tformat: 2") print("\tfeatures: layering, exclusive-lock") if eltern: print("\tparent: %s" % eltern) print("\toverlap: %d GiB" % gigabyte) return 0 if befehl == "snap" and len(rest) > 1 and rest[1] == "ls": abbild, _ = teile(rest[2] if len(rest) > 2 else "") eintraege = [{"id": nummer + 1, "name": name, "size": GROESSEN.get(abbild, 32) * 1024 ** 3, "protected": "true" if geschuetzt else "false"} for nummer, (name, geschuetzt) in enumerate(SNAPSHOTS.get(abbild, []))] if optionen.get("--format") == "json": print(json.dumps(eintraege)) else: for e in eintraege: print("%4d %-40s %10d" % (e["id"], e["name"], e["size"])) return 0 if befehl == "snap" and len(rest) > 1 and rest[1] in ("unprotect", "protect"): abbild, _ = teile(rest[2] if len(rest) > 2 else "") name = optionen.get("--snap") or "" vorhanden = [s for s, _ in SNAPSHOTS.get(abbild, [])] if name not in vorhanden: print("rbd: snapshot '%s' does not exist" % name, file=sys.stderr) return 2 if rest[1] == "unprotect" and kinder(abbild, name): print("rbd: snapshot '%s' is protected from unprotection" % name, file=sys.stderr) return 16 return 0 if befehl == "children": for kind in kinder(abbild, snap): print("vmdaten/%s" % kind) return 0 if befehl in ("du", "flatten"): print("NAME PROVISIONED USED") print("%-19s 400 GiB 2.4 GiB" % abbild) return 0 return 0 if __name__ == "__main__": sys.exit(main(sys.argv[1:]))