From c33ba5927ac5d907abdf1341ed0e9f697c7734ec Mon Sep 17 00:00:00 2001 From: Alvin Ge Date: Mon, 29 Apr 2024 02:37:11 +0000 Subject: [PATCH] match string logic corrected; ready for testing on k8s cluster --- helper.py | 63 +++++++++++++++++++++++++--------------------- main.py | 48 +++++++++++++++++++++-------------- nginx/Dockerfile | 11 ++++++++ nginx/default.conf | 19 ++++++++++++++ parsing.py | 9 +++++++ test.py | 6 +++++ 6 files changed, 108 insertions(+), 48 deletions(-) create mode 100644 nginx/Dockerfile create mode 100644 nginx/default.conf create mode 100644 parsing.py create mode 100644 test.py diff --git a/helper.py b/helper.py index e477927..cb2b46d 100755 --- a/helper.py +++ b/helper.py @@ -1,7 +1,7 @@ #!/usr/bin/python3 # helper.py -import os, socket, requests +import os, socket, requests, json from cloudflare_dns import find_record, add_record, delete_record get_timeout = int(os.environ["GET_TIMEOUT"]) @@ -9,6 +9,7 @@ down_threshold = int(os.environ["DOWN_THRESHOLD"]) dns_cache = {} + # override the default dns resolver that requests.get calls under the hood prv_getaddrinfo = socket.getaddrinfo def new_getaddrinfo(*args): @@ -18,59 +19,63 @@ def new_getaddrinfo(*args): return prv_getaddrinfo(*args) socket.getaddrinfo = new_getaddrinfo -def parse_domains_env_var(env_var_value): - domains = {} +def get_hosts_from_env(): + return json.loads(os.environ["HOSTS"]) - domain_parts = env_var_value.split(';') - for domain_part in domain_parts: - subdomain_parts = domain_part.split(':') - domain_name = subdomain_parts[0] - domains[domain_name] = {} - subdomain_parts = subdomain_parts[1:] - for subdomain_part in subdomain_parts: - ip_parts = subdomain_part.split(',') - subdomain_name = ip_parts[0] - domains[domain_name][subdomain_name] = ip_parts[1:] - - return domains +def within_range(status_code_range, status_code): + for code_or_range in status_code_range: + if isinstance(code_or_range, int): + if status_code == code_or_range: + return True + elif isinstance(code_or_range, list) and len(code_or_range) == 2: + start, end = code_or_range + if start <= status_code and status_code <= end: + return True + else: + raise TypeError("A status code range is in a wrong format") + return False -def get_domains_from_env(): - env_var_value = os.getenv('DOMAINS', '') - return parse_domains_env_var(env_var_value) +def string_match(string1, string2): + return string1==string2 def monitor(subdomain, FQDN, ip_addr_list, uptime, downtime, recorded, zone_id): for i in range(len(ip_addr_list)): try: - dns_cache[FQDN] = ip_addr_list[i] - response = requests.get(f"http://{FQDN}", timeout=get_timeout) - print(f"{FQDN}: {ip_addr_list[i]} UP") + dns_cache[FQDN] = ip_addr_list[i]["ip_address"] + # TODO: add path in the URL + response = requests.get(f"http://{FQDN}:{ip_addr_list[i]['port']}", timeout=get_timeout) + # TODO: make default range an environment variable + status_code_range = ip_addr_list[i]["status_code_range"] if ip_addr_list[i].get("status_code_range") else [[200, 299]] + if not within_range(status_code_range, int(response.status_code)) or not string_match(ip_addr_list[i]["match_string"], response.text): + raise requests.RequestException() + print(f"{FQDN}: {ip_addr_list[i]['ip_address']} with port {ip_addr_list[i]['port']} and path {ip_addr_list[i]['path']} UP") uptime[i] += 1 downtime[i] = 0 if not recorded[i] and uptime[i] >= up_threshold: # add record to cloudflare dns zone - success = add_record(ip_addr_list[i], subdomain, zone_id) + success = add_record(ip_addr_list[i]["ip_address"], subdomain, zone_id) if success: - print(f"{FQDN}: {ip_addr_list[i]} ADD SUCCESSFUL") + print(f"{FQDN}: {ip_addr_list[i]['ip_address']} ADD SUCCESSFUL") recorded[i] = True else: - print(f"{FQDN}: {ip_addr_list[i]} ADD FAILED") + print(f"{FQDN}: {ip_addr_list[i]['ip_address']} ADD FAILED") uptime[i] == 0 except: # failed connection (node is potentially down) - print(f"{FQDN}: {ip_addr_list[i]} NO ANSWER") + print(f"{FQDN}: {ip_addr_list[i]['ip_address']} NO ANSWER") uptime[i] = 0 downtime[i] += 1 if downtime[i] == down_threshold and recorded[i]: # find dns id of the host - record_id, found = find_record(ip_addr_list[i], FQDN, zone_id) + record_id, found = find_record(ip_addr_list[i]["ip_address"], FQDN, zone_id) if found: # delete record from cloudflare dns zone success = delete_record(record_id, zone_id) if success: recorded[i] = False - print(f"{FQDN}: {ip_addr_list[i]} DELETE SUCCESSFUL") + print(f"{FQDN}: {ip_addr_list[i]['ip_address']} DELETE SUCCESSFUL") else: - print(f"{FQDN}: ATTENTION! couldn't delete {ip_addr_list[i]} with its record id") + print(f"{FQDN}: ATTENTION! couldn't delete {ip_addr_list[i]['ip_address']} with its record id") else: - print(f"{FQDN}: record id of {ip_addr_list[i]} cannot be found on cloudflare") + print(f"{FQDN}: record id of {ip_addr_list[i]['ip_address']} cannot be found on cloudflare") downtime[i] = 0 diff --git a/main.py b/main.py index bd8f263..29de541 100755 --- a/main.py +++ b/main.py @@ -1,32 +1,36 @@ #!/usr/bin/python3 # main.py -import time, os +import time, os, json, sys from cloudflare_dns import find_record, find_zones_under_account -from helper import get_domains_from_env, monitor +from helper import get_hosts_from_env, monitor # reading environment variable delay = int(os.environ["DELAY"]) -domain_subdomain_ips = get_domains_from_env() # dictionary of domain to ip_addrs +domain_subdomain_ips = get_hosts_from_env() # dictionary of domain to ip_addrs cloudflare_refresh_period_ticks = int(os.environ["CLOUDFLARE_REFRESH_PERIOD_TICKS"]) # dictionary of domain to zone_id domain_dict = find_zones_under_account() +# check domain_subdomain_ips +# print(json.dumps(domain_subdomain_ips, indent=2)) print(domain_dict) -print(domain_subdomain_ips) # initialization of variables uptime = {} downtime = {} recorded = {} -for domain in domain_subdomain_ips: - for subdomain in domain_subdomain_ips[domain]: - FQDN = subdomain + '.' + domain - ip_addr_list = domain_subdomain_ips[domain][subdomain] +for domain in domain_subdomain_ips["domains"]: + domain_name = domain["domain_name"] + subdomains = domain_subdomain_ips["domains"][domain_name]["subdomains"] + for subdomain in subdomains: + subdomain_name = subdomain["subdomain_name"] + FQDN = subdomain_name + '.' + domain_name + ip_addr_list = subdomain["ip_addresses"] uptime[FQDN] = [0] * len(ip_addr_list) downtime[FQDN] = [0] * len(ip_addr_list) - recorded[FQDN] = [find_record(ip_addr_list[i], FQDN, domain_dict[domain])[1] for i in range(len(ip_addr_list))] + recorded[FQDN] = [find_record(ip_addr_list[i], FQDN, domain_dict[domain_name])[1] for i in range(len(ip_addr_list))] # infinite loop count = 0 @@ -37,16 +41,22 @@ # will add the record back up if someone manually deletes it on cloudflare by accident count += 1 if count == cloudflare_refresh_period_ticks: - for domain in domain_subdomain_ips: - for subdomain in domain_subdomain_ips[domain]: - FQDN = subdomain + '.' + domain - ip_addr_list = domain_subdomain_ips[domain][subdomain] - recorded[FQDN] = [find_record(ip_addr_list[i], FQDN, domain_dict[domain])[1] for i in range(len(ip_addr_list))] + for domain in domain_subdomain_ips["domains"]: + domain_name = domain["domain_name"] + subdomains = domain_subdomain_ips["domains"][domain_name]["subdomains"] + for subdomain in subdomains: + subdomain_name = subdomain["subdomain_name"] + FQDN = subdomain_name + '.' + domain_name + ip_addr_list = subdomain["ip_addresses"] + recorded[FQDN] = [find_record(ip_addr_list[i], FQDN, domain_dict[domain_name])[1] for i in range(len(ip_addr_list))] count = 0 # actual work - for domain in domain_subdomain_ips: - for subdomain in domain_subdomain_ips[domain]: - FQDN = subdomain + '.' + domain - ip_addr_list = domain_subdomain_ips[domain][subdomain] - monitor(subdomain, FQDN, ip_addr_list, uptime[FQDN], downtime[FQDN], recorded[FQDN], domain_dict[domain]) + for domain in domain_subdomain_ips["domains"]: + domain_name = domain["domain_name"] + subdomains = domain_subdomain_ips["domains"][domain_name]["subdomains"] + for subdomain in subdomains: + subdomain_name = subdomain["subdomain_name"] + FQDN = subdomain_name + '.' + domain_name + ip_addr_list = subdomain["ip_addresses"] + monitor(subdomain_name, FQDN, ip_addr_list, uptime[FQDN], downtime[FQDN], recorded[FQDN], domain_dict[domain_name]) diff --git a/nginx/Dockerfile b/nginx/Dockerfile new file mode 100644 index 0000000..5f2dbfe --- /dev/null +++ b/nginx/Dockerfile @@ -0,0 +1,11 @@ +# Use the official Nginx image as a parent image +FROM nginx:latest + +# Copy the custom Nginx config file into the container +COPY default.conf /etc/nginx/conf.d/default.conf + +# Expose port 80 +EXPOSE 80 + +# Start Nginx when the container has provisioned +CMD ["nginx", "-g", "daemon off;"] diff --git a/nginx/default.conf b/nginx/default.conf new file mode 100644 index 0000000..56f2392 --- /dev/null +++ b/nginx/default.conf @@ -0,0 +1,19 @@ +server { + listen 80; + server_name localhost; + + location / { + default_type text/plain; + return 220 'Welcome to /. Cheers!\n'; + } + + location /path1 { + default_type text/plain; + return 220 'Welcome to /path1. Cheers!\n'; + } + + location /path/two { + default_type text/plain; + return 220 'Welcome to /path/two. Cheers!\n'; + } +} diff --git a/parsing.py b/parsing.py new file mode 100644 index 0000000..76c8b9a --- /dev/null +++ b/parsing.py @@ -0,0 +1,9 @@ +import json, os, time + +json_string = os.environ["HOSTS"] + +json_object = json.loads(json_string) +formatted_json_string = json.dumps(json_object, indent=2) +print(formatted_json_string) + +time.sleep(20) diff --git a/test.py b/test.py new file mode 100644 index 0000000..bab8d4e --- /dev/null +++ b/test.py @@ -0,0 +1,6 @@ +import requests + +response = requests.request("GET", "http://10.0.50.114:8080") +print(type(response.text)) # str +print(response.text) +print(response.status_code)