summaryrefslogtreecommitdiff
path: root/lib/gitlab/database/load_balancing/srv_resolver.rb
blob: 1f599ef4a273f9dc48d7cc727d23a96eefd75208 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# frozen_string_literal: true

require 'net/dns'

module Gitlab
  module Database
    module LoadBalancing
      # Hostnames returned in SRV records cannot sometimes be resolved by a local
      # resolver, however, there's a possibility that their A/AAAA records are
      # returned as part of the SRV query in the additional section, so we try
      # to extract the IPs from there first, failing back to querying the
      # hostnames A/AAAA records one by one, using the same resolver that
      # queried the SRV record.
      class SrvResolver
        include Gitlab::Utils::StrongMemoize

        attr_reader :resolver, :additional

        def initialize(resolver, additional)
          @resolver = resolver
          @additional = additional
        end

        def address_for(host)
          addresses_from_additional[host] || resolve_host(host)
        end

        private

        def addresses_from_additional
          strong_memoize(:addresses_from_additional) do
            additional.each_with_object({}) do |rr, h|
              h[rr.name] = rr.address if rr.is_a?(Net::DNS::RR::A) || rr.is_a?(Net::DNS::RR::AAAA)
            end
          end
        end

        def resolve_host(host)
          record = resolver.search(host, Net::DNS::ANY).answer.find do |rr|
            rr.is_a?(Net::DNS::RR::A) || rr.is_a?(Net::DNS::RR::AAAA)
          end

          record&.address
        end
      end
    end
  end
end