#!/usr/bin/env python3 import asyncio import ecs_logging import logging import os import sys from kubernetes_asyncio.client.api_client import ApiClient from kubernetes_asyncio import client, config, watch from time import time # Get the Logger logger = logging.getLogger() logger.setLevel(logging.INFO) # Add an ECS formatter to the Handler handler = logging.StreamHandler() handler.setFormatter(ecs_logging.StdlibFormatter()) logger.addHandler(handler) ZONEFILE_TEMPLATE = """ @ IN SOA ns1.%(zone)s. hostmaster.%(zone)s. (2022060820 300 300 300 300) NS ns1.%(zone)s. ns1 A %(ip)s """ _, ip = sys.argv PATH_CONFIG = "/var/bind/bind.conf" PATH_ZONEFILE = "/var/bind/db.%s" active_zones = set() def update_config(): with open(PATH_CONFIG + ".part", "w") as fh: for zone in active_zones: path = PATH_ZONEFILE % zone fh.write("zone \"%s\" { type master; file \"%s\"; };\n" % (zone, path)) os.rename(PATH_CONFIG + ".part", PATH_CONFIG) async def update_loop(v1, apps_api, api_instance, revision): flt = "codemowers.io", "v1alpha1", "bindzones" method = api_instance.list_cluster_custom_object w = watch.Watch() latest_version = None logger.info("Subscribing to updates") async for event in w.stream(method, *flt, resource_version=latest_version): latest_version = event["object"]["metadata"]["resourceVersion"] if event["type"] == "ADDED": zone = event["object"]["metadata"]["name"] active_zones.add(zone) path = PATH_ZONEFILE % zone logger.info("Adding zone: %s", zone) if not os.path.exists(path): with open(path + ".part", "w") as fh: fh.write(ZONEFILE_TEMPLATE % { "ip": ip, "zone": zone }) os.rename(path + ".part", path) update_config() elif event["type"] == "DELETED": logger.info("Removing zone: %s", zone) active_zones.remove(zone) os.unlink(PATH_ZONEFILE % event["object"]["metadata"]["name"]) async def main(): if os.getenv("KUBECONFIG"): await config.load_kube_config() else: config.load_incluster_config() async with ApiClient() as api: v1 = client.CoreV1Api(api) apps_api = client.AppsV1Api() api_instance = client.CustomObjectsApi(api) revision = str(time()) while True: try: await update_loop(v1, apps_api, api_instance, revision) except asyncio.exceptions.TimeoutError: pass if __name__ == "__main__": loop = asyncio.new_event_loop() loop.run_until_complete(main()) loop.close()