import requests from typing import NamedTuple import re import sys import operator TRAEFIK_HOST_RE = re.compile(r"Host\(`([a-z0-9\.-]+)`\)") class Route(NamedTuple): name: str destination: str hostname: str def parse_traefik_rule(rule: str) -> list[str]: if "Host(" not in rule: return [] return TRAEFIK_HOST_RE.findall(rule) def get_traefik_routes(traefik_host: str, traefik_route: str): api_response = requests.get(f"{traefik_host}/api/http/routers").json() routes = set() for router in api_response: hosts = parse_traefik_rule(router["rule"]) if not hosts: print(f"Failed to find host for {router['rule']}", file=sys.stderr) continue if len(hosts) > 1: print(f"WARNING: Found multiple hosts for rule: {router['rule']}", file=sys.stderr) routes.add(Route( router["service"], traefik_route, hosts[0] )) return routes def get_dokku_routes(dokku_exporter_url: str, dokku_route: str): api_response = requests.get(dokku_exporter_url).json() routes = set() for app in api_response: for vhost in app["vhosts"]: routes.add(Route( app["app"], dokku_route, vhost )) return routes def main(): routes = [] routes.extend(get_traefik_routes("http://10.23.1.103:8080", "http://10.23.1.103")) routes.extend(get_dokku_routes("http://10.23.2.3:8000", "http://10.23.2.3")) for route in sorted(routes, key=operator.attrgetter("hostname")): print(f"{route.hostname}\t{route.destination}; # {route.name}") if __name__ == "__main__": main()