Created
January 3, 2019 01:33
-
-
Save undeadops/1ea2101fa3001c90f332fdc5e2c6956b to your computer and use it in GitHub Desktop.
Watch upstream dns entries for changes, reload nginx based on changes
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# Watch for DNS changes for heroku | |
import logging | |
from logging.handlers import SysLogHandler | |
import socket | |
import os | |
import yaml | |
import sys | |
import argparse | |
from datetime import datetime | |
from subprocess import Popen, PIPE | |
# Because readability in data file is important | |
try: import simplejson as json | |
except ImportError: import json | |
# Because its not part of stdlib, importing here to gain logging | |
try: | |
import dns.resolver | |
except ImportError, e: | |
print "Missing DNSPython: %s" % e | |
print "Install with: apt-get install python-dnspython" | |
sys.exit(1) | |
class DNSWatcher: | |
def __init__(self, quiet=False): | |
""" | |
Setup Logging and state file | |
""" | |
self.logger = logging.getLogger(name="DNSWatcher") | |
self.logger.setLevel(logging.INFO) | |
if quiet: | |
handler = SysLogHandler(address = '/dev/log') | |
else: | |
handler = logging.StreamHandler(sys.stdout) | |
formatter = logging.Formatter('DNSWatcher: %(message)s') | |
handler.setFormatter(formatter) | |
self.logger.addHandler(handler) | |
# Do I need to reload nginx | |
self.reload_nginx = False | |
self.logger.info("DNS Watcher Is Starting...") | |
try: | |
with open('/etc/dnswatcher.cfg') as fh: | |
self.cfg = yaml.load(fh) | |
except IOError, e: | |
self.logger.critical("Config Missing: /etc/dnswatcher.cfg") | |
sys.exit(2) | |
self.data = self._load_datafile() | |
if self.cfg['heroku-hosts'] != None: | |
self._proccess_hosts() | |
def _reload_nginx(self): | |
""" | |
Reload Nginx | |
""" | |
self.logger.warning("Reloading Nginx") | |
process = Popen(['/usr/sbin/service','nginx','reload'], stdout=PIPE) | |
(output, err) = process.communicate() | |
exit_code = process.wait() | |
if exit_code != 0: | |
self.logger.critical("ERROR Reloading Nginx! I hope its still up...") | |
else: | |
self.logger.warning("Success! Reload of Nginx complete.") | |
def _load_datafile(self): | |
""" | |
Look for datafile, create if nessisary | |
""" | |
if os.path.isfile('/var/cache/dnswatcher'): | |
with open('/var/cache/dnswatcher', 'r') as fh: | |
data = json.load(fh) | |
fh.close() | |
else: | |
data = {} | |
return data | |
def _write_datafile(self): | |
""" | |
Write DNS Lookup result to datafile | |
""" | |
try: | |
with open('/var/cache/dnswatcher', 'w') as fh: | |
json.dump(self.data, fh, indent=1) | |
fh.close() | |
except IOError, e: | |
self.logger.critical("Error writing data file: %s" % e) | |
sys.exit(2) | |
def _query_dns(self, host): | |
""" | |
Perform DNS lookup, return IP's | |
""" | |
result = dns.resolver.query(host, 'A') | |
host_ips = [] | |
for r in result: | |
host_ips.append(r.to_text()) | |
self.logger.info("%s -> %s" % (host, host_ips)) | |
return host_ips | |
def _compare_hosts_dns(self,host,cur_ips): | |
""" | |
Perform Comparison of current host ips with stored | |
""" | |
data = {} | |
try: | |
prev_ips = self.data[host]['ips'] | |
except KeyError: | |
data[host] = {'updated': datetime.now().strftime("%c")} | |
data[host] = {'ips': cur_ips } | |
self.data.update(data) | |
prev_ips = None | |
self.logger.info("Adding new host lookup: %s" % host) | |
# I know these will be a list of 3 IP's always... | |
if prev_ips != None: | |
diff = list(set(cur_ips) - set(prev_ips)) | |
if len(diff) > 0: | |
self.logger.info("Oy! DNS Changes afoot for host: %s" % host) | |
self.logger.warning("New IPs: %s | Old IPs: %s" % (cur_ips, prev_ips)) | |
data[host] = {'updated': datetime.now().strftime("%c")} | |
data[host] = {'ips': cur_ips } | |
self.data.update(data) | |
self.reload_nginx = True | |
def _proccess_hosts(self): | |
""" | |
Load heroku hosts, | |
""" | |
for host in self.cfg['heroku-hosts']: | |
ips = self._query_dns(host) | |
self._compare_hosts_dns(host,ips) | |
self._write_datafile() | |
if self.reload_nginx == True: | |
self.logger.info("Oy! Reloading Nginx!") | |
self._reload_nginx() | |
def main(): | |
""" | |
Watch for DNS changes in Heroku | |
Reload Nginx if there are changes | |
""" | |
parser = argparse.ArgumentParser(description='Check for IP Changes on Heroku Hosts') | |
parser.add_argument('--quiet', action='store_true', help='Send Logging to Syslog') | |
args = parser.parse_args() | |
dns = DNSWatcher(quiet=args.quiet) | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Example /etc/dnswatcher.cfg