all repos — janny @ 9f26b2436e13adeca2721f669d3d8368735d340b

clean up Kubernetes resources after a set TTL

Implement deletion of resource according to TTL
Anirudh Oppiliappan x@icyphox.sh
Mon, 08 Mar 2021 22:00:12 +0530
commit

9f26b2436e13adeca2721f669d3d8368735d340b

parent

efbb09b9be2e820ddec0280db023c0a05e7d7ff6

3 files changed, 67 insertions(+), 9 deletions(-)

jump to
A janny/cleanup.py

@@ -0,0 +1,25 @@

+import time +import logging +import datetime + +from janny.utils import parse_delta, get +from janny.auth import SESSION as s +from janny.config import API_HOST + +logging.basicConfig(level=logging.INFO) + + +def clean_up( + url: str, kube_resource: str, resource_name: str, kill_time: str, namespace: str +): + delta = parse_delta(kill_time) + secs = delta.total_seconds() + time.sleep(secs) + logging.info(f"Slept for {kill_time}. Cleaning resource {resource_name} now.") + send_delete_event(url, kube_resource, resource_name, namespace) + logging.info(f"Sent delete event to {kube_resource}/{resource_name}") + + +def send_delete_event(url: str, kube_resource: str, resource_name: str, namespace: str): + api_url = f"{API_HOST}/{url}/namespaces/{namespace}/{kube_resource}/{resource_name}" + s.delete(api_url, params={"propagationPolicy": "Background"})
M janny/main.pyjanny/main.py

@@ -1,4 +1,10 @@

+import threading +import logging + from janny.utils import get +from janny.cleanup import clean_up + +logging.basicConfig(level=logging.INFO) def get_resource_urls() -> list:

@@ -35,22 +41,25 @@

return filtered_resource_list -def check_annotations(resource_tuple: tuple, namespace: str) -> list: +def spawn_clean_up_job(resource_tuple: tuple, namespace: str): """ - Returns a list of resource tuples which have the 'janny.ttl' - annotation. + Spawns a clean up job -- runs on a new thread. """ url, resource = resource_tuple resource_list = get(f"{url}/namespaces/{namespace}/{resource.name}") - annotated_list = list() for r in resource_list.items: if "janny.ttl" in vars(r.metadata.annotations): - annotated_list.append(r) - - return annotated_list + print(r.metadata.annotations) + kill_time = vars(r.metadata.annotations)["janny.ttl"] + t = threading.Thread( + target=clean_up, + args=[url, resource.name, r.metadata.name, kill_time, namespace], + ) + logging.info(f"Starting cleaner thread for {r.metadata.name}") + t.start() def main(): filtered = filter_included_resources(["deployments"], get_resource_urls()) for f in filtered: - print(check_annotations(f, "default")) + spawn_clean_up_job(f, "default")
M janny/utils.pyjanny/utils.py

@@ -1,14 +1,38 @@

import logging import json +import re +from datetime import timedelta from types import SimpleNamespace from janny.config import API_HOST from janny.auth import SESSION -def get(path): +def get(path: str) -> SimpleNamespace: """Convert a JSON response into a Python object""" s = SESSION data = s.get(API_HOST + path).content obj = json.loads(data, object_hook=lambda d: SimpleNamespace(**d)) return obj + + +timedelta_regex = ( + r"((?P<days>-?\d+)d)?" r"((?P<hours>-?\d+)h)?" r"((?P<minutes>-?\d+)m)?" +) + +timedelta_pattern = re.compile(timedelta_regex, re.IGNORECASE) + + +def parse_delta(delta: str) -> timedelta: + """Parses a human readable timedelta (3d5h19m) into a datetime.timedelta. + Delta includes: + * Xd days + * Xh hours + * Xm minutes + Values can be negative following timedelta's rules. Eg: -5h-30m + """ + match = timedelta_pattern.match(delta) + if match: + parts = {k: int(v) for k, v in match.groupdict().items() if v} + return timedelta(**parts) + return timedelta(0)