render-vps-configs: print masked unified diff in --dry-run
Lets the operator see exactly what would change on the VPS before applying. Secret values from the decrypted sops files are masked as <REDACTED> so the diff is safe to paste into chat/PRs.
This commit is contained in:
25
bin/homelab
25
bin/homelab
@@ -703,6 +703,7 @@ def _vps_send(remote_path: str, content: str, mode: str) -> None:
|
|||||||
def cmd_render_vps_configs(args: argparse.Namespace) -> int:
|
def cmd_render_vps_configs(args: argparse.Namespace) -> int:
|
||||||
"""Re-render /etc/turnserver.conf + /opt/management.json on the IONOS netbird
|
"""Re-render /etc/turnserver.conf + /opt/management.json on the IONOS netbird
|
||||||
VPS from templates in vps/, substituting secrets decrypted from sops."""
|
VPS from templates in vps/, substituting secrets decrypted from sops."""
|
||||||
|
import difflib
|
||||||
# Decrypt the two sops files we need.
|
# Decrypt the two sops files we need.
|
||||||
turn = _decrypt_secret("turn-shared-secret")
|
turn = _decrypt_secret("turn-shared-secret")
|
||||||
auth = _decrypt_secret("netbird-authentik-oidc")
|
auth = _decrypt_secret("netbird-authentik-oidc")
|
||||||
@@ -727,6 +728,7 @@ def cmd_render_vps_configs(args: argparse.Namespace) -> int:
|
|||||||
plans.append({
|
plans.append({
|
||||||
**t,
|
**t,
|
||||||
"rendered": rendered,
|
"rendered": rendered,
|
||||||
|
"current": current,
|
||||||
"changed": current != rendered,
|
"changed": current != rendered,
|
||||||
"current_present": cat.returncode == 0 and bool(current),
|
"current_present": cat.returncode == 0 and bool(current),
|
||||||
})
|
})
|
||||||
@@ -743,8 +745,29 @@ def cmd_render_vps_configs(args: argparse.Namespace) -> int:
|
|||||||
print("Nothing to do — every target matches the rendered template.")
|
print("Nothing to do — every target matches the rendered template.")
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
# Show diffs (always — both dry-run and live).
|
||||||
|
print()
|
||||||
|
for p in plans:
|
||||||
|
if not p["changed"]:
|
||||||
|
continue
|
||||||
|
print(f"--- diff for {p['remote']} ---")
|
||||||
|
# Mask any sops-decrypted secret values so they don't print to stdout.
|
||||||
|
def _mask(s):
|
||||||
|
for v in subs.values():
|
||||||
|
s = s.replace(v, "<REDACTED>")
|
||||||
|
return s
|
||||||
|
diff = difflib.unified_diff(
|
||||||
|
_mask(p["current"]).splitlines(keepends=True),
|
||||||
|
_mask(p["rendered"]).splitlines(keepends=True),
|
||||||
|
fromfile=f"vps:{p['remote']}",
|
||||||
|
tofile=f"rendered:{p['tmpl']}",
|
||||||
|
n=3,
|
||||||
|
)
|
||||||
|
sys.stdout.writelines(diff)
|
||||||
|
print()
|
||||||
|
|
||||||
if args.dry_run:
|
if args.dry_run:
|
||||||
print("\n--- dry-run: not applying ---")
|
print("--- dry-run: not applying ---")
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
if not args.yes:
|
if not args.yes:
|
||||||
|
|||||||
Reference in New Issue
Block a user