# Copyright The IETF Trust 2024, All Rights Reserved # # Uses only Python standard lib # import argparse import datetime import json import shutil import stat import sys from pathlib import Path from tempfile import TemporaryDirectory # Default options POSTCONFIRM_PATH = "/a/postconfirm/wrapper" VDOMAIN = "virtual.ietf.org" # Map from domain label to dns domain ADOMAINS = { "ietf": "ietf.org", "irtf": "irtf.org", "iab": "iab.org", } def generate_files(records, adest, vdest, postconfirm, vdomain): """Generate files from an iterable of records If adest or vdest exists as a file, it will be overwritten. If it is a directory, files with the default names (draft-aliases and draft-virtual) will be created, but existing files _will not_ be overwritten! """ with TemporaryDirectory() as tmpdir: tmppath = Path(tmpdir) apath = tmppath / "aliases" vpath = tmppath / "virtual" with apath.open("w") as afile, vpath.open("w") as vfile: date = datetime.datetime.now(datetime.timezone.utc) signature = f"# Generated by {Path(__file__).absolute()} at {date}\n" afile.write(signature) vfile.write(signature) vfile.write(f"{vdomain} anything\n") for item in records: alias = item["alias"] domains = item["domains"] address_list = item["addresses"] filtername = f"xfilter-{alias}" afile.write(f'{filtername + ":":64s} "|{postconfirm} filter expand-{alias} {vdomain}"\n') for dom in domains: vfile.write(f"{f'{alias}@{ADOMAINS[dom]}':64s} {filtername}\n") vfile.write(f"{f'expand-{alias}@{vdomain}':64s} {', '.join(sorted(address_list))}\n") perms = stat.S_IWUSR | stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH apath.chmod(perms) vpath.chmod(perms) shutil.move(apath, adest) shutil.move(vpath, vdest) if __name__ == "__main__": parser = argparse.ArgumentParser( description="Convert a JSON stream of draft alias definitions into alias / virtual alias files." ) parser.add_argument( "--prefix", required=True, help="Prefix for output files. Files will be named -aliases and -virtual." ) parser.add_argument( "--output-dir", default="./", type=Path, help="Destination for output files.", ) parser.add_argument( "--postconfirm", default=POSTCONFIRM_PATH, help=f"Full path to postconfirm executable (defaults to {POSTCONFIRM_PATH}", ) parser.add_argument( "--vdomain", default=VDOMAIN, help=f"Virtual domain (defaults to {VDOMAIN}_", ) args = parser.parse_args() if not args.output_dir.is_dir(): sys.stderr.write("Error: output-dir must be a directory") data = json.load(sys.stdin) generate_files( data["aliases"], adest=args.output_dir / f"{args.prefix}-aliases", vdest=args.output_dir / f"{args.prefix}-virtual", postconfirm=args.postconfirm, vdomain=args.vdomain, )