Skip to content

Instantly share code, notes, and snippets.

@SamSaffron
Created November 22, 2018 06:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save SamSaffron/97d95cc75b5e812e0a7d3e712c8b16ea to your computer and use it in GitHub Desktop.
Save SamSaffron/97d95cc75b5e812e0a7d3e712c8b16ea to your computer and use it in GitHub Desktop.
require 'resolv'
require 'time'
require 'timeout'
# HOSTS = "/etc/hosts"
HOSTS_PATH = "hosts"
CRITICAL_HOST_ENV_VARS = %w{
DISCOURSE_DB_HOST
DISCOURSE_DB_BACKUP_HOST
DISCOURSE_REDIS_HOST
DISCOURSE_REDIS_SLAVE_HOST
}
def log(msg)
STDERR.puts "#{Time.now.iso8601}: #{msg}"
end
def error(msg)
log(msg)
end
def swap_address(hosts, name, ips)
new_file = []
hosts.split("\n").each do |line|
line = line.strip
if line[0] != '#'
_, hostname = line.strip.split(/\s+/)
next if hostname == name
end
new_file << line
end
ips.each do |ip|
new_file << "#{ip} #{name} # AUTO GENERATED: #{Time.now.iso8601}"
end
new_file.join("\n")
end
def hosts_entries(dns, name)
host = ENV[name]
results = dns.getresources(host, Resolv::DNS::Resource::IN::A)
results.concat dns.getresources(host, Resolv::DNS::Resource::IN::AAAA)
results.map do |result|
"#{result.address}"
end
end
def send_counter(name, description, labels, value)
end
def report_success
send_counter('critical_dns_successes_total', 'critical DNS resolution success')
end
def report_failure(errors)
errors.each do |host, count|
send_counter('critical_dns_failures_total', 'critical DNS resolution failures', host ? { host: host } : nil, count)
end
end
@vars = CRITICAL_HOST_ENV_VARS.map do |name|
begin
host = ENV[name]
next if !host || host.length == 0
IPAddr.new(ENV[name])
nil
rescue IPAddr::InvalidAddressError, IPAddr::AddressFamilyError
name
end
end.compact
def loop
errors = {}
Resolv::DNS.open do |dns|
dns.timeouts = 2
resolved = {}
hosts = @vars.each do |var|
host = ENV[var]
begin
entries = hosts_entries(dns, var)
rescue => e
error("Failed to resolve DNS for #{name} - #{e}")
errors[host] ||= 0
errors[host] += 1
end
if entries&.length > 0
resolved[host] = entries
else
error("Failed to find any DNS entry for #{var} : #{ENV[var]}")
errors[host] ||= 0
errors[host] += 1
end
end
hosts_content = File.read(HOSTS_PATH)
hosts = Resolv::Hosts.new(HOSTS)
changed = false
resolved.each do |name, ips|
if hosts.getaddresses(name).map(&:to_s).sort != ips.sort
log("IP addresses for #{name} changed to #{ips}")
hosts_content = swap_address(hosts_content, name, ips)
changed = true
end
end
if changed
File.write(HOSTS, hosts_content)
end
end
rescue => e
error("Failed to access DNS - #{e}")
errors[nil] = 1
ensure
if errors == 0
report_success
else
report_failure(errors)
end
end
while true
loop
#CHANGE ME
sleep 1
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment