1
Fork 0
This repository has been archived on 2023-11-05. You can view files and clone it, but cannot push or open issues or pull requests.
dynamic-nginx-host-map/create-nginx-map.py
2023-10-31 19:15:26 +00:00

99 lines
2.4 KiB
Python

import requests
from typing import NamedTuple
import re
import sys
import tomllib
from pathlib import Path
from typing import TypedDict
from collections import defaultdict
TRAEFIK_HOST_RE = re.compile(r"Host\(`([a-z0-9\.-]+)`\)")
CONFIG_FILE = Path.cwd() / "config.toml"
class Route(NamedTuple):
name: str
destination: str
hostname: str
class Source(TypedDict):
type: str
url: str
destination: str
class Config(TypedDict):
source: list[Source]
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():
config: Config = tomllib.loads(CONFIG_FILE.read_text())
routes = []
for source in config["source"]:
match source["type"]:
case "traefik":
routes.extend(get_traefik_routes(source["url"], source["destination"]))
case "dokku":
routes.extend(get_dokku_routes(source["url"], source["destination"]))
if len(routes) != len(set(routes)):
raise ValueError("Conflict found!")
grouped_routes = defaultdict(set)
for route in routes:
grouped_routes[route.hostname, route.destination].add(route.name)
for (hostname, destination), names in sorted(grouped_routes.items()):
print(f"{hostname}\t{destination}; # {', '.join(names)}")
print("Found", len(routes), "routes, grouped into", len(grouped_routes), "groups")
if __name__ == "__main__":
main()