Skip to content

Commit

Permalink
match string logic corrected; ready for testing on k8s cluster
Browse files Browse the repository at this point in the history
  • Loading branch information
Feinburger committed Apr 29, 2024
1 parent 4963034 commit c33ba59
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 48 deletions.
63 changes: 34 additions & 29 deletions helper.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
#!/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"])
up_threshold = int(os.environ["UP_THRESHOLD"])
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):
Expand All @@ -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
48 changes: 29 additions & 19 deletions main.py
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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])
11 changes: 11 additions & 0 deletions nginx/Dockerfile
Original file line number Diff line number Diff line change
@@ -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;"]
19 changes: 19 additions & 0 deletions nginx/default.conf
Original file line number Diff line number Diff line change
@@ -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';
}
}
9 changes: 9 additions & 0 deletions parsing.py
Original file line number Diff line number Diff line change
@@ -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)
6 changes: 6 additions & 0 deletions test.py
Original file line number Diff line number Diff line change
@@ -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)

0 comments on commit c33ba59

Please sign in to comment.