From 47d581a6ac1d44de991097a67e4d00de74985b74 Mon Sep 17 00:00:00 2001 From: "T. Andrew Manning" Date: Tue, 17 Dec 2024 08:58:21 -0600 Subject: [PATCH 1/6] Add SUPPORT_LEGACY_CRDS env var to optionally disable watcher for traefik.containo.us/v1alpha1/ingressroute --- main.py | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/main.py b/main.py index 7e6dc3d..b87ba84 100644 --- a/main.py +++ b/main.py @@ -19,6 +19,7 @@ CERT_ISSUER_NAME = os.getenv("ISSUER_NAME", "letsencrypt") CERT_ISSUER_KIND = os.getenv("ISSUER_KIND", "ClusterIssuer") CERT_CLEANUP = os.getenv("CERT_CLEANUP", "false").lower() in ("yes", "true", "t", "1") PATCH_SECRETNAME = os.getenv("PATCH_SECRETNAME", "false").lower() in ("yes", "true", "t", "1") +SUPPORT_LEGACY_CRDS = os.getenv("SUPPORT_LEGACY_CRDS", "true").lower() in ("yes", "true", "t", "1") def safe_get(obj, keys, default=None): @@ -147,19 +148,25 @@ def main(): signal.signal(signal.SIGINT, exit_gracefully) signal.signal(signal.SIGTERM, exit_gracefully) - # deprecated traefik CRD - th1 = threading.Thread(target=watch_crd, args=("traefik.containo.us", "v1alpha1", "ingressroutes"), daemon=True) + # new traefik CRD + th1 = threading.Thread(target=watch_crd, args=("traefik.io", "v1alpha1", "ingressroutes"), daemon=True) th1.start() - # new traefik CRD - th2 = threading.Thread(target=watch_crd, args=("traefik.io", "v1alpha1", "ingressroutes"), daemon=True) - th2.start() + if SUPPORT_LEGACY_CRDS: + # deprecated traefik CRD + th2 = threading.Thread(target=watch_crd, args=("traefik.containo.us", "v1alpha1", "ingressroutes"), daemon=True) + th2.start() - # wait for threads to finish - while th1.is_alive() and th2.is_alive(): - th1.join(0.1) - th2.join(0.1) - logging.info(f"One of the threads exited {th1.is_alive()}, {th2.is_alive()}") + # wait for threads to finish + while th1.is_alive() and th2.is_alive(): + th1.join(0.1) + th2.join(0.1) + logging.info(f"traefik.containo.us/v1alpha1/ingressroutes watcher exited {th2.is_alive()}") + else: + # wait for threads to finish + while th1.is_alive(): + th1.join(0.1) + logging.info(f"traefik.io/v1alpha1/ingressroutes watcher exited {th1.is_alive()}") if __name__ == '__main__': From ad07deae24fe94a495226465215d1a3cd8513188 Mon Sep 17 00:00:00 2001 From: "T. Andrew Manning" Date: Tue, 17 Dec 2024 08:58:29 -0600 Subject: [PATCH 2/6] Python linting --- main.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/main.py b/main.py index b87ba84..dc8c217 100644 --- a/main.py +++ b/main.py @@ -6,7 +6,6 @@ import signal import sys import threading -from unicodedata import name from kubernetes import client, config, watch from kubernetes.client.rest import ApiException @@ -39,10 +38,10 @@ def create_certificate(crds, namespace, secretname, routes): Create a certificate request for certmanager based on the IngressRoute """ try: - secret = crds.get_namespaced_custom_object(CERT_GROUP, CERT_VERSION, namespace, CERT_PLURAL, secretname) + # secret = crds.get_namespaced_custom_object(CERT_GROUP, CERT_VERSION, namespace, CERT_PLURAL, secretname) logging.info(f"{secretname} : certificate request already exists.") return - except ApiException as e: + except ApiException: pass for route in routes: @@ -88,7 +87,7 @@ def watch_crd(group, version, plural): """ Watch Traefik IngressRoute CRD and create/delete certificates based on them """ - #config.load_kube_config() + # config.load_kube_config() config.load_incluster_config() crds = client.CustomObjectsApi() resource_version = "" @@ -117,7 +116,7 @@ def watch_crd(group, version, plural): # if no secretName is set, add one to the IngressRoute if not secretname and PATCH_SECRETNAME: logging.info(f"{namespace}/{name} : no secretName found in IngressRoute, patch to add one") - patch = { "spec": { "tls": { "secretName": name }}} + patch = {"spec": {"tls": {"secretName": name}}} crds.patch_namespaced_custom_object(group, version, namespace, plural, name, patch) secretname = name if secretname: From 601a4bf78d196977c38a034637f3d467aa04f9f9 Mon Sep 17 00:00:00 2001 From: "T. Andrew Manning" Date: Tue, 17 Dec 2024 08:58:54 -0600 Subject: [PATCH 3/6] Pin kubernetes Python package at v31 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 807e21b..67ac26f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1 @@ -kubernetes +kubernetes==31.x From 80ef73fe58e31a80c5c5fd084bf8dc6b51c57ab0 Mon Sep 17 00:00:00 2001 From: "T. Andrew Manning" Date: Tue, 17 Dec 2024 08:59:09 -0600 Subject: [PATCH 4/6] Pin Docker image to Python 3.11-alpine --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index cb3575e..9032f6a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM python:alpine +FROM python:3.11-alpine ENV PYTHONUNBUFFERED=1 \ ISSUER_NAME=letsencrypt \ From 7cbec8882688dbfaa55f2c1a566614c989d3bb1e Mon Sep 17 00:00:00 2001 From: "T. Andrew Manning" Date: Tue, 17 Dec 2024 08:59:28 -0600 Subject: [PATCH 5/6] Avoid build warning by using JSON list in CMD --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 9032f6a..dc2e0e5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,4 +8,4 @@ ENV PYTHONUNBUFFERED=1 \ RUN pip install kubernetes COPY main.py / -CMD python /main.py +CMD ["python", "/main.py"] From aeaccb9d140f79ed595ec5af613bf07788baaf67 Mon Sep 17 00:00:00 2001 From: "T. Andrew Manning" Date: Tue, 17 Dec 2024 11:30:39 -0600 Subject: [PATCH 6/6] Restore search for existing certificate --- main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.py b/main.py index dc8c217..f91e930 100644 --- a/main.py +++ b/main.py @@ -38,7 +38,7 @@ def create_certificate(crds, namespace, secretname, routes): Create a certificate request for certmanager based on the IngressRoute """ try: - # secret = crds.get_namespaced_custom_object(CERT_GROUP, CERT_VERSION, namespace, CERT_PLURAL, secretname) + assert crds.get_namespaced_custom_object(CERT_GROUP, CERT_VERSION, namespace, CERT_PLURAL, secretname) logging.info(f"{secretname} : certificate request already exists.") return except ApiException: