debian-mirror-gitlab/lib/gitlab/database/load_balancing/resolver.rb
2023-03-17 16:20:25 +05:30

71 lines
1.8 KiB
Ruby

# frozen_string_literal: true
require 'net/dns'
require 'resolv'
module Gitlab
module Database
module LoadBalancing
class Resolver
FAR_FUTURE_TTL = 100.years.from_now
UnresolvableNameserverError = Class.new(StandardError)
Response = Class.new do
attr_reader :address, :ttl
def initialize(address:, ttl:)
raise ArgumentError unless ttl.present? && address.present?
@address = address
@ttl = ttl
end
end
def initialize(nameserver)
@nameserver = nameserver
end
def resolve
address = ip_address || ip_address_from_hosts_file ||
ip_address_from_dns
unless address
raise UnresolvableNameserverError,
"could not resolve #{@nameserver}"
end
address
end
private
def ip_address
# IP addresses are valid forever
Response.new(address: IPAddr.new(@nameserver), ttl: FAR_FUTURE_TTL)
rescue IPAddr::InvalidAddressError
end
def ip_address_from_hosts_file
ip = Resolv::Hosts.new.getaddress(@nameserver)
Response.new(address: IPAddr.new(ip), ttl: FAR_FUTURE_TTL)
rescue Resolv::ResolvError
end
def ip_address_from_dns
answer = Net::DNS::Resolver.start(@nameserver, Net::DNS::A).answer
return if answer.empty?
raw_response = answer.first
# Defaults to 30 seconds if there is no TTL present
ttl_in_seconds = raw_response.ttl.presence || 30
Response.new(address: answer.first.address, ttl: ttl_in_seconds.seconds.from_now)
rescue Net::DNS::Resolver::NoResponseError
raise UnresolvableNameserverError, "no response from DNS server(s)"
end
end
end
end
end