Skip to content

Commit 7bcfbd7

Browse files
committed
Add support for connecting to nodes by their hostname
1 parent 45973e0 commit 7bcfbd7

File tree

3 files changed

+50
-27
lines changed

3 files changed

+50
-27
lines changed

lib/dns_cluster.ex

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@ defmodule DNSCluster do
5151
differs between nodes, a tuple of `{basename, query}` can be provided as well.
5252
The value `:ignore` can be used to ignore starting the DNSCluster.
5353
* `:resource_types` - the resource record types that are used for node discovery.
54-
Defaults to `[:a, :aaaa]` and also supports the `:srv` type.
54+
Defaults to `[:a, :aaaa]` and also supports `{:srv, :ips}`, `{:srv, :hostnames}` and
55+
`:srv` (same as `{:srv, :ips}`) type.
5556
* `:interval` - the millisec interval between DNS queries. Defaults to `5000`.
5657
* `:connect_timeout` - the millisec timeout to allow discovered nodes to connect.
5758
Defaults to `10_000`.
@@ -68,7 +69,7 @@ defmodule DNSCluster do
6869
GenServer.start_link(__MODULE__, opts, name: Keyword.get(opts, :name, __MODULE__))
6970
end
7071

71-
@valid_resource_types [:a, :aaaa, :srv]
72+
@valid_resource_types [:a, :aaaa, :srv, {:srv, :ips}, {:srv, :hostnames}]
7273

7374
@impl true
7475
def init(opts) do
@@ -79,7 +80,11 @@ defmodule DNSCluster do
7980
{:ok, query} ->
8081
validate_query!(query)
8182

82-
resource_types = Keyword.get(opts, :resource_types, [:a, :aaaa])
83+
resource_types =
84+
opts
85+
|> Keyword.get(:resource_types, [:a, :aaaa])
86+
|> normalize_old_srv_resource_type()
87+
8388
validate_resource_types!(resource_types)
8489

8590
warn_on_invalid_dist()
@@ -161,12 +166,22 @@ defmodule DNSCluster do
161166
{basename, addr}
162167
end
163168
|> Enum.uniq()
164-
|> Enum.map(fn {basename, addr} -> {basename, to_string(:inet.ntoa(addr))} end)
169+
|> Enum.map(fn
170+
{basename, ip} when is_tuple(ip) -> {basename, to_string(:inet.ntoa(ip))}
171+
{basename, hostname} -> {basename, hostname}
172+
end)
165173
end
166174

167175
defp basename_from_query_or_state({basename, _query}, _state), do: basename
168176
defp basename_from_query_or_state(_query, %{basename: basename}), do: basename
169177

178+
defp normalize_old_srv_resource_type(resource_types) do
179+
Enum.map(resource_types, fn
180+
:srv -> {:srv, :ips}
181+
resource_type -> resource_type
182+
end)
183+
end
184+
170185
defp validate_query!(query) do
171186
query
172187
|> List.wrap()
@@ -186,7 +201,7 @@ defmodule DNSCluster do
186201
defp validate_resource_types!(resource_types) do
187202
if resource_types == [] or resource_types -- @valid_resource_types != [] do
188203
raise ArgumentError,
189-
"expected :resource_types to be a subset of [:a, :aaaa, :srv], got: #{inspect(resource_types)}"
204+
"expected :resource_types to be a subset of #{inspect(@valid_resource_types)}, got: #{inspect(resource_types)}"
190205
end
191206
end
192207

lib/dns_cluster/resolver.ex

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,30 +13,36 @@ defmodule DNSCluster.Resolver do
1313

1414
def list_nodes, do: Node.list(:visible)
1515

16-
def lookup(query, type) when is_binary(query) and type in [:a, :aaaa] do
17-
case :inet_res.getbyname(~c"#{query}", type) do
18-
{:ok, hostent(h_addr_list: addr_list)} -> addr_list
19-
{:error, _} -> []
20-
end
16+
def lookup(query, {:srv, :hostnames}), do: lookup_by_name(query, :srv)
17+
18+
def lookup(query, {:srv, :ips}) do
19+
query
20+
|> lookup_by_name(:srv)
21+
|> Enum.flat_map(&lookup_host_by_name/1)
2122
end
2223

23-
def lookup(query, type) when is_binary(query) and type in [:srv] do
24-
case :inet_res.getbyname(~c"#{query}", type) do
25-
{:ok, hostent(h_addr_list: srv_list)} ->
26-
lookup_hosts(srv_list)
24+
def lookup(query, resource_type) when resource_type in [:a, :aaaa] do
25+
lookup_by_name(query, resource_type)
26+
end
2727

28-
{:error, _} ->
28+
defp lookup_by_name(query, resource_type) do
29+
case :inet_res.getbyname(~c"#{query}", resource_type) do
30+
{:ok, hostent(h_addr_list: addr_list)} ->
31+
if resource_type == :srv do
32+
for {_prio, _weight, _port, address} <- addr_list, do: address
33+
else
34+
addr_list
35+
end
36+
37+
{:error, _reason} ->
2938
[]
3039
end
3140
end
3241

33-
defp lookup_hosts(srv_list) do
34-
srv_list
35-
|> Enum.flat_map(fn {_prio, _weight, _port, host_name} ->
36-
case :inet.gethostbyname(host_name) do
37-
{:ok, hostent(h_addr_list: addr_list)} -> addr_list
38-
{:error, _} -> []
39-
end
40-
end)
42+
defp lookup_host_by_name(query) do
43+
case :inet_res.gethostbyname(query) do
44+
{:ok, hostent(h_addr_list: addr_list)} -> addr_list
45+
{:error, _reason} -> []
46+
end
4147
end
4248
end

test/dns_cluster_test.exs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,8 @@ defmodule DNSClusterTest do
141141
end
142142

143143
describe "resource_types" do
144-
test "resource_types can be a subset of [:a, :aaaa, :srv]", config do
144+
test "resource_types can be a subset of [:a, :aaaa, :srv, {:srv, :ips}, {:srv, :hostnames}]",
145+
config do
145146
assert {:ok, _cluster} =
146147
start_supervised(
147148
{DNSCluster,
@@ -152,9 +153,10 @@ defmodule DNSClusterTest do
152153
)
153154
end
154155

155-
test "resource_types can't be outside of [:a, :aaaa, :srv]", config do
156+
test "resource_types can't be outside of [:a, :aaaa, :srv, {:srv, :ips}, {:srv, :hostnames}]",
157+
config do
156158
assert_raise RuntimeError,
157-
~r/expected :resource_types to be a subset of \[:a, :aaaa, :srv\]/,
159+
~r/expected :resource_types to be a subset of \[:a, :aaaa, :srv, {:srv, :ips}, {:srv, :hostnames}\]/,
158160
fn ->
159161
start_supervised!(
160162
{DNSCluster,
@@ -168,7 +170,7 @@ defmodule DNSClusterTest do
168170

169171
test "resource_types can't be empty", config do
170172
assert_raise RuntimeError,
171-
~r/expected :resource_types to be a subset of \[:a, :aaaa, :srv\]/,
173+
~r/expected :resource_types to be a subset of \[:a, :aaaa, :srv, {:srv, :ips}, {:srv, :hostnames}\]/,
172174
fn ->
173175
start_supervised!(
174176
{DNSCluster,

0 commit comments

Comments
 (0)