diff --git a/extract-fw-host-vars.py b/extract-fw-host-vars.py index d7fcd26..32e7e11 100755 --- a/extract-fw-host-vars.py +++ b/extract-fw-host-vars.py @@ -3,13 +3,17 @@ Extract ipt-firewall configuration from a host and generate host_vars YAML. Reads /etc/ipt-firewall/{interfaces,main}_ipv{4,6}.conf via SSH, -maps all variables to Ansible fw_* names, and writes a host_vars file. +maps all variables to Ansible fw_* names, and writes a host_vars file +(default: host_vars//-ipt-server.yml next to this +script; an existing file is only overwritten with --force). Usage: - ./extract-fw-host-vars.py [--user USER] [--port PORT] [--sudo] [--from-dir DIR] [--output FILE] [--dry-run] + ./extract-fw-host-vars.py [--user USER] [--port PORT] [--sudo] [--from-dir DIR] + [--output FILE|-] [--force] [--dry-run] Example: - ./extract-fw-host-vars.py cl-01.oopen.de + ./extract-fw-host-vars.py cl-01.oopen.de # -> host_vars/cl-01.oopen.de/cl-01-ipt-server.yml + ./extract-fw-host-vars.py cl-01.oopen.de -o - # print to stdout ./extract-fw-host-vars.py cl-01.oopen.de --user root --dry-run """ @@ -746,7 +750,10 @@ def main(): parser.add_argument("hostname", help="Target hostname (must be in SSH config or known_hosts)") parser.add_argument("--user", "-u", default="chris", help="SSH user (default: chris)") parser.add_argument("--port", "-p", type=int, default=None, help="SSH port (default: 22)") - parser.add_argument("--output", "-o", default=None, help="Output file (default: stdout)") + parser.add_argument("--output", "-o", default=None, + help="Output file, '-' for stdout " + "(default: host_vars//-ipt-server.yml)") + parser.add_argument("--force", "-f", action="store_true", help="Overwrite an existing output file") parser.add_argument("--sudo", "-s", action="store_true", help="Read files via sudo (prompts for sudo password once)") parser.add_argument("--from-dir", "-d", default=None, @@ -770,6 +777,21 @@ def main(): print(f"ssh {args.user}@{hostname} {cmd} {path}") return + # Determine the output file first, so an existing file aborts before any SSH + out_path = None + if args.output != "-": + if args.output: + out_path = Path(args.output) + else: + # Same as ${HOSTNAME%.*.*} in the docs: a.mx.oopen.de -> a.mx + short = hostname.rsplit(".", 2)[0] if hostname.count(".") >= 2 else hostname + out_path = Path(__file__).resolve().parent / "host_vars" / hostname / f"{short}-ipt-server.yml" + + if out_path.exists() and not args.force: + print(f"ERROR: {out_path} already exists — use --force to overwrite " + "or -o - to print to stdout", file=sys.stderr) + sys.exit(1) + contents = {} if args.from_dir: for key, path in files.items(): @@ -814,13 +836,13 @@ def main(): yaml_text = render_yaml(hostname, host_vars, all_warnings) - if args.output: - out_path = Path(args.output) - out_path.parent.mkdir(parents=True, exist_ok=True) - out_path.write_text(yaml_text) - print(f"Written to {out_path}", file=sys.stderr) - else: + if out_path is None: print(yaml_text) + return + + out_path.parent.mkdir(parents=True, exist_ok=True) + out_path.write_text(yaml_text) + print(f"Written to {out_path}", file=sys.stderr) if __name__ == "__main__": diff --git a/roles/ipt-server/MIGRATION.md b/roles/ipt-server/MIGRATION.md index cbfc470..cdf7c74 100644 --- a/roles/ipt-server/MIGRATION.md +++ b/roles/ipt-server/MIGRATION.md @@ -56,12 +56,15 @@ mappt alle Variablen auf die `fw_*`-Ansible-Variablen und schreibt eine fertige cd /path/to/ansible/oopen-server HOSTNAME= -./extract-fw-host-vars.py ${HOSTNAME} --sudo \ - -o host_vars/${HOSTNAME}/${HOSTNAME%.*.*}-ipt-server.yml +./extract-fw-host-vars.py ${HOSTNAME} --sudo ``` -Das Skript fragt einmalig nach dem `sudo`-Passwort. Kann eine der Dateien nicht -gelesen werden, bricht es ab, ohne etwas zu schreiben. +Das Skript fragt einmalig nach dem `sudo`-Passwort und schreibt nach +`host_vars/${HOSTNAME}/${HOSTNAME%.*.*}-ipt-server.yml`. Eine vorhandene Datei +wird nur mit `--force` überschrieben (dabei wird `fw_manage_config` wieder +`false`); mit `-o -` geht die Ausgabe nach stdout, mit `-o DATEI` in eine +andere Datei. Kann eine der Conf-Dateien nicht gelesen werden, bricht das +Skript ab, ohne etwas zu schreiben. Alternativ ohne Passwortabfrage (sudo über `ansible_become_password` aus dem Vault): die Dateien mit Ansible holen und lokal einlesen: @@ -71,8 +74,7 @@ for f in interfaces_ipv4 interfaces_ipv6 main_ipv4 main_ipv6 ; do ansible ${HOSTNAME} -b -m fetch \ -a "src=/etc/ipt-firewall/${f}.conf dest=/tmp/fw-${HOSTNAME}/ flat=yes" done -./extract-fw-host-vars.py ${HOSTNAME} --from-dir /tmp/fw-${HOSTNAME} \ - -o host_vars/${HOSTNAME}/${HOSTNAME%.*.*}-ipt-server.yml +./extract-fw-host-vars.py ${HOSTNAME} --from-dir /tmp/fw-${HOSTNAME} rm -rf /tmp/fw-${HOSTNAME} ```