@@ -58,6 +58,26 @@ defmodule DNSCluster do
5858 { :error , _ } -> [ ]
5959 end
6060 end
61+
62+ def lookup ( query , type ) when is_binary ( query ) and type in [ :srv ] do
63+ case :inet_res . getbyname ( ~c" #{ query } " , type ) do
64+ { :ok , hostent ( h_addr_list: srv_list ) } ->
65+ lookup_hosts ( srv_list )
66+
67+ { :error , _ } ->
68+ [ ]
69+ end
70+ end
71+
72+ defp lookup_hosts ( srv_list ) do
73+ srv_list
74+ |> Enum . flat_map ( fn { _prio , _weight , _port , host_name } ->
75+ case :inet . gethostbyname ( host_name ) do
76+ { :ok , hostent ( h_addr_list: addr_list ) } -> addr_list
77+ { :error , _ } -> [ ]
78+ end
79+ end )
80+ end
6181 end
6282
6383 @ doc ~S"""
@@ -70,6 +90,8 @@ defmodule DNSCluster do
7090 `"myapp.internal"` or `["foo.internal", "bar.internal"]`. If the basename
7191 differs between nodes, a tuple of `{basename, query}` can be provided as well.
7292 The value `:ignore` can be used to ignore starting the DNSCluster.
93+ * `:resource_types` - the resource record types that are used for node discovery.
94+ Defaults to `[:a, :aaaa]` and also supports the `:srv` type.
7395 * `:interval` - the millisec interval between DNS queries. Defaults to `5000`.
7496 * `:connect_timeout` - the millisec timeout to allow discovered nodes to connect.
7597 Defaults to `10_000`.
@@ -86,33 +108,43 @@ defmodule DNSCluster do
86108 GenServer . start_link ( __MODULE__ , opts , name: Keyword . get ( opts , :name , __MODULE__ ) )
87109 end
88110
111+ @ valid_resource_types [ :a , :aaaa , :srv ]
112+
89113 @ impl true
90114 def init ( opts ) do
115+ resource_types = Keyword . get ( opts , :resource_types , [ :a , :aaaa ] )
116+
91117 case Keyword . fetch ( opts , :query ) do
92118 { :ok , :ignore } ->
93119 :ignore
94120
95121 { :ok , query } ->
96- if valid_query? ( query ) do
97- warn_on_invalid_dist ( )
98- resolver = Keyword . get ( opts , :resolver , Resolver )
99-
100- state = % {
101- interval: Keyword . get ( opts , :interval , 5_000 ) ,
102- basename: resolver . basename ( node ( ) ) ,
103- query: List . wrap ( query ) ,
104- log: Keyword . get ( opts , :log , false ) ,
105- poll_timer: nil ,
106- connect_timeout: Keyword . get ( opts , :connect_timeout , 10_000 ) ,
107- resolver: resolver
108- }
109-
110- { :ok , state , { :continue , :discover_ips } }
111- else
122+ if not valid_query? ( query ) do
112123 raise ArgumentError ,
113124 "expected :query to be a string, {basename, query}, or list, got: #{ inspect ( query ) } "
114125 end
115126
127+ if not valid_resource_types? ( resource_types ) do
128+ raise ArgumentError ,
129+ "expected :resource_types to be a subset of [:a, :aaaa, :srv], got: #{ inspect ( resource_types ) } "
130+ end
131+
132+ warn_on_invalid_dist ( )
133+ resolver = Keyword . get ( opts , :resolver , Resolver )
134+
135+ state = % {
136+ interval: Keyword . get ( opts , :interval , 5_000 ) ,
137+ basename: resolver . basename ( node ( ) ) ,
138+ query: List . wrap ( query ) ,
139+ resource_types: resource_types ,
140+ log: Keyword . get ( opts , :log , false ) ,
141+ poll_timer: nil ,
142+ connect_timeout: Keyword . get ( opts , :connect_timeout , 10_000 ) ,
143+ resolver: resolver
144+ }
145+
146+ { :ok , state , { :continue , :discover_ips } }
147+
116148 :error ->
117149 raise ArgumentError , "missing required :query option in #{ inspect ( opts ) } "
118150 end
@@ -165,8 +197,8 @@ defmodule DNSCluster do
165197 % { state | poll_timer: Process . send_after ( self ( ) , :discover_ips , state . interval ) }
166198 end
167199
168- defp discover_ips ( % { resolver: resolver , query: queries } = state ) do
169- [ :a , :aaaa ]
200+ defp discover_ips ( % { resolver: resolver , query: queries , resource_types: resource_types } = state ) do
201+ resource_types
170202 |> Enum . flat_map ( fn type ->
171203 Enum . flat_map ( queries , fn query ->
172204 { basename , query } =
@@ -199,6 +231,12 @@ defmodule DNSCluster do
199231 end )
200232 end
201233
234+ defp valid_resource_types? ( [ ] ) , do: false
235+
236+ defp valid_resource_types? ( resource_types ) do
237+ resource_types -- @ valid_resource_types == [ ]
238+ end
239+
202240 defp warn_on_invalid_dist do
203241 release? = is_binary ( System . get_env ( "RELEASE_NAME" ) )
204242 net_state = if function_exported? ( :net_kernel , :get_state , 0 ) , do: :net_kernel . get_state ( )
0 commit comments