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()
for app in api_response:
for vhost in app["vhosts"]:
app["app"],
dokku_route,
vhost
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()