"""Namensschema der von pvesnap verwalteten Snapshots. Ein Name sieht so aus: auto-taeglich-20260730-023000 ^^^^ ^^^^^^^^ ^^^^^^^^ ^^^^^^ | | Datum Uhrzeit | Kurzname der Gruppe Praefix aus [global] Nur Snapshots, die exakt auf dieses Muster passen, werden von pvesnap angefasst. Von Hand angelegte Snapshots bleiben damit garantiert unberuehrt. """ from __future__ import annotations import re from datetime import datetime # Proxmox erlaubt fuer Snapshot-Namen nur begrenzte Laenge - wir bleiben # bewusst deutlich darunter. MAX_NAME_LEN = 40 _STAMP_LEN = len("-20260730-023000") def max_slug_len(prefix): return max(1, MAX_NAME_LEN - len(prefix) - _STAMP_LEN) def effective_slug(prefix, slug): """Der Kurzname, wie er tatsaechlich im Snapshot-Namen landet.""" return slug[: max_slug_len(prefix)] def build_name(prefix, slug, moment): return "%s-%s-%s" % (prefix, effective_slug(prefix, slug), moment.strftime("%Y%m%d-%H%M%S")) def name_pattern(prefix, slug=None): part = re.escape(effective_slug(prefix, slug)) if slug else r"[A-Za-z0-9]+" return re.compile(r"^%s-(%s)-(\d{8})-(\d{6})$" % (re.escape(prefix), part)) def parse_name(prefix, name): """Zerlegt einen Snapshot-Namen; gibt None zurueck, wenn er nicht zu uns gehoert.""" match = name_pattern(prefix).match(str(name)) if not match: return None slug, date_part, time_part = match.groups() try: created = datetime.strptime(date_part + time_part, "%Y%m%d%H%M%S") except ValueError: return None return {"slug": slug, "created": created} def render_description(template, group, guest, moment, prefix): """Setzt die Platzhalter der Beschreibungs-Vorlage ein.""" from .util import format_duration # lokal, um Zyklen zu vermeiden values = { "prefix": prefix, "group": group.name, "group_slug": group.slug, "vmid": guest.vmid, "name": guest.name or "", "type": "LXC" if guest.type == "lxc" else "VM", "node": guest.node or "", "pool": guest.pool or "", "tags": ",".join(guest.tags), "date": moment.strftime("%Y-%m-%d"), "time": moment.strftime("%H:%M:%S"), "datetime": moment.strftime("%Y-%m-%d %H:%M:%S"), "timestamp": int(moment.timestamp()), "keep_time": format_duration(group.keep_time), "keep_count": group.keep_count if group.keep_count else "unbegrenzt", "schedule": _schedule_text(group), } try: text = str(template).format(**values) except (KeyError, IndexError, ValueError): # Unbekannter Platzhalter: lieber eine brauchbare Beschreibung als ein Abbruch. text = "pvesnap | Gruppe: %s | erstellt: %s" % (group.name, values["datetime"]) return text.strip()[:1024] def _schedule_text(group): from .schedule import describe return describe(group)