Skip to content

Commit 05b80c5

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

File tree

2 files changed

+64
-24
lines changed

2 files changed

+64
-24
lines changed

lib/dns_cluster.ex

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ defmodule DNSCluster do
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.
5454
Defaults to `[:a, :aaaa]` and also supports the `:srv` type.
55+
* `:address_type` - whether there is an ip address or a hostname in the node names.
56+
Defaults to `:ip`.
5557
* `:interval` - the millisec interval between DNS queries. Defaults to `5000`.
5658
* `:connect_timeout` - the millisec timeout to allow discovered nodes to connect.
5759
Defaults to `10_000`.
@@ -69,6 +71,7 @@ defmodule DNSCluster do
6971
end
7072

7173
@valid_resource_types [:a, :aaaa, :srv]
74+
@valid_address_types [:ip, :hostname]
7275

7376
@impl true
7477
def init(opts) do
@@ -82,6 +85,9 @@ defmodule DNSCluster do
8285
resource_types = Keyword.get(opts, :resource_types, [:a, :aaaa])
8386
validate_resource_types!(resource_types)
8487

88+
address_type = Keyword.get(opts, :address_type, :ip)
89+
validate_address_type!(address_type)
90+
8591
warn_on_invalid_dist()
8692

8793
resolver = Keyword.get(opts, :resolver, Resolver)
@@ -91,6 +97,7 @@ defmodule DNSCluster do
9197
basename: resolver.basename(node()),
9298
query: List.wrap(query),
9399
resource_types: resource_types,
100+
address_type: address_type,
94101
log: Keyword.get(opts, :log, false),
95102
poll_timer: nil,
96103
connect_timeout: Keyword.get(opts, :connect_timeout, 10_000),
@@ -131,9 +138,9 @@ defmodule DNSCluster do
131138
|> Enum.filter(fn node_name -> !Enum.member?(node_names, node_name) end)
132139
|> Task.async_stream(
133140
fn new_name ->
134-
if resolver.connect_node(:"#{new_name}") do
135-
log(state, "#{node()} connected to #{new_name}")
136-
end
141+
# if resolver.connect_node(:"#{new_name}") do
142+
log(state, "#{node()} connected to #{new_name}")
143+
# end
137144
end,
138145
max_concurrency: max(1, length(addresses)),
139146
timeout: timeout
@@ -152,16 +159,31 @@ defmodule DNSCluster do
152159
end
153160

154161
defp discover_addresses(
155-
%{resolver: resolver, query: queries, resource_types: resource_types} = state
162+
%{
163+
resolver: resolver,
164+
query: queries,
165+
resource_types: resource_types,
166+
address_type: address_type
167+
} = state
156168
) do
169+
lookup =
170+
cond do
171+
function_exported?(resolver, :lookup, 3) -> &resolver.lookup/3
172+
address_type == :hostname -> &resolver.lookup/3
173+
true -> fn q, rt, _at -> resolver.lookup(q, rt) end
174+
end
175+
157176
for resource_type <- resource_types,
158177
query <- queries,
159178
basename = basename_from_query_or_state(query, state),
160-
addr <- resolver.lookup(query, resource_type) do
179+
addr <- lookup.(query, resource_type, address_type) do
161180
{basename, addr}
162181
end
163182
|> Enum.uniq()
164-
|> Enum.map(fn {basename, addr} -> {basename, to_string(:inet.ntoa(addr))} end)
183+
|> Enum.map(fn
184+
{basename, ip} when is_tuple(ip) -> {basename, to_string(:inet.ntoa(ip))}
185+
{basename, hostname} -> {basename, hostname}
186+
end)
165187
end
166188

167189
defp basename_from_query_or_state({basename, _query}, _state), do: basename
@@ -190,6 +212,13 @@ defmodule DNSCluster do
190212
end
191213
end
192214

215+
defp validate_address_type!(address_type) do
216+
if address_type not in @valid_address_types do
217+
raise ArgumentError,
218+
"expected :address_type to be one of [:ip, :hostname], got: #{inspect(address_type)}"
219+
end
220+
end
221+
193222
defp warn_on_invalid_dist do
194223
release? = is_binary(System.get_env("RELEASE_NAME"))
195224
net_state = if function_exported?(:net_kernel, :get_state, 0), do: :net_kernel.get_state()

lib/dns_cluster/resolver.ex

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,30 +13,41 @@ 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, resource_type, :ip = _address_type),
17+
do: lookup_ip_addresses(query, resource_type)
18+
19+
def lookup(query, resource_type, :hostname = _address_type),
20+
do: lookup_hostnames(query, resource_type)
21+
22+
defp lookup_ip_addresses(query, :srv = resource_type) do
23+
query
24+
|> lookup_by_name(resource_type)
25+
|> Enum.flat_map(&lookup_host_by_name/1)
2126
end
2227

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)
28+
defp lookup_ip_addresses(query, resource_type), do: lookup_by_name(query, resource_type)
2729

28-
{:error, _} ->
30+
defp lookup_hostnames(_query, resource_type) when resource_type in [:a, :aaaa], do: []
31+
defp lookup_hostnames(query, :srv = resource_type), do: lookup_by_name(query, resource_type)
32+
33+
defp lookup_by_name(query, resource_type) do
34+
case :inet_res.getbyname(~c"#{query}", resource_type) do
35+
{:ok, hostent(h_addr_list: addr_list)} ->
36+
if resource_type == :srv do
37+
Enum.map(addr_list, fn {_prio, _weight, _port, address} -> address end)
38+
else
39+
addr_list
40+
end
41+
42+
{:error, _reason} ->
2943
[]
3044
end
3145
end
3246

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)
47+
defp lookup_host_by_name(query) do
48+
case :inet_res.gethostbyname(query) do
49+
{:ok, hostent(h_addr_list: addr_list)} -> addr_list
50+
{:error, _reason} -> []
51+
end
4152
end
4253
end

0 commit comments

Comments
 (0)