This is an automated email from the ASF dual-hosted git repository.
kocolosk pushed a commit to branch dns-cluster-discovery
in repository https://gitbox.apache.org/repos/asf/couchdb.git
commit f3a2fb165fea4aee4f42ce0fbcd98ba461c26c84
Author: Adam Kocoloski <kocolosk@apache.org>
AuthorDate: Fri Jan 12 22:16:49 2018 -0500
Enable discovery of cluster nodes through DNS SRV
This patch enables CouchDB nodes to check SRV records in DNS for cluster
peers and automatically add any discovered peers to the nodes DB. This
behavior is disabled by default and can be enabled as follows:
[mem3]
use_dns_service_discovery = true
service_record_name = _couchdb._tcp.example.net
If the `service_record_name` is omitted we attempt to generate the
appropriate record for the query by prepending _couchdb._tcp. to the DNS
domain name portion of the host / VM / container FQDN.
---
src/mem3/src/mem3_dns.erl | 109 ++++++++++++++++++++++++++++++++++++++++++++
src/mem3/src/mem3_nodes.erl | 1 +
src/mem3/src/mem3_sup.erl | 1 +
3 files changed, 111 insertions(+)
diff --git a/src/mem3/src/mem3_dns.erl b/src/mem3/src/mem3_dns.erl
new file mode 100644
index 0000000..0a954fd
--- /dev/null
+++ b/src/mem3/src/mem3_dns.erl
@@ -0,0 +1,109 @@
+% Licensed under the Apache License, Version 2.0 (the "License"); you may not
+% use this file except in compliance with the License. You may obtain a copy of
+% the License at
+%
+% http://www.apache.org/licenses/LICENSE-2.0
+%
+% Unless required by applicable law or agreed to in writing, software
+% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+% License for the specific language governing permissions and limitations under
+% the License.
+
+-module(mem3_dns).
+-behaviour(gen_server).
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
+ code_change/3]).
+
+-export([start_link/0]).
+-export([discover_peers/0]).
+
+-include_lib("couch/include/couch_db.hrl").
+
+-record(state, {
+ record_name,
+ discovered_names,
+ last_error,
+ timeout = 2000,
+ max_tries = 10
+}).
+
+start_link() ->
+ gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
+
+discover_peers() ->
+ case config:get("mem3", "use_dns_service_discovery", "false") of
+ "true" ->
+ gen_server:cast(?MODULE, discover_peers);
+ _ ->
+ ok
+ end.
+
+init([]) ->
+ {ok, ServiceRecord} = construct_service_record(),
+ {ok, #state{record_name = ServiceRecord}}.
+
+handle_call(_Call, _From, State) ->
+ {reply, ok, State}.
+
+handle_cast(discover_peers, #state{max_tries = 0} = State) ->
+ {ok, State};
+
+handle_cast(discover_peers, St) ->
+ case query_dns(St#state.record_name) of
+ {ok, Hostnames} ->
+ add_nodes(Hostnames),
+ {ok, St#state{discovered_names = Hostnames}};
+ {error, Error} ->
+ #state{max_tries = Max, timeout = Timeout} = St,
+ NewSt = St#state{
+ last_error = Error,
+ max_tries = Max-1,
+ timeout = 2*Timeout
+ },
+ {ok, NewSt, Timeout}
+ end.
+
+handle_info(timeout, State) ->
+ handle_cast(discover_peers, State).
+
+terminate(_Reason, _State) ->
+ ok.
+
+code_change(_OldVsn, #state{}=State, _Extra) ->
+ {ok, State}.
+
+query_dns(ServiceRecord) ->
+ Opts = [{edns, 0}],
+ case inet_res:resolve(ServiceRecord, in, srv, Opts) of
+ {ok, DnsMsg} ->
+ Hostnames = lists:foldl(fun(Answer, Acc) ->
+ case inet_dns:rr(Answer, type) of
+ srv ->
+ {_, _, _, Service} = inet_dns:rr(Answer, data),
+ [Service | Acc];
+ _ ->
+ Acc
+ end
+ end, [], inet_dns:msg(DnsMsg, anlist)),
+ {ok, Hostnames};
+ Error ->
+ Error
+ end.
+
+construct_service_record() ->
+ case config:get("mem3", "service_record_name") of
+ undefined ->
+ [_ | Domain] = string:tokens(net_adm:localhost(), "."),
+ {ok, string:join(["_couchdb", "_tcp" | Domain], ".")};
+ ServiceRecord ->
+ {ok, ServiceRecord}
+ end.
+
+add_nodes(Hostnames) ->
+ DbName = config:get("mem3", "nodes_db", "_nodes"),
+ {ok, Db} = mem3_util:ensure_exists(DbName),
+ Peers = lists:map(fun(Hostname) ->
+ #doc{id = couch_util:to_binary("couchdb@" ++ Hostname)}
+ end, Hostnames),
+ couch_db:update_docs(Db, Peers, []).
diff --git a/src/mem3/src/mem3_nodes.erl b/src/mem3/src/mem3_nodes.erl
index 555389b..02f1a2d 100644
--- a/src/mem3/src/mem3_nodes.erl
+++ b/src/mem3/src/mem3_nodes.erl
@@ -43,6 +43,7 @@ get_node_info(Node, Key) ->
init([]) ->
ets:new(?MODULE, [named_table, {read_concurrency, true}]),
UpdateSeq = initialize_nodelist(),
+ mem3_dns:discover_peers(),
{Pid, _} = spawn_monitor(fun() -> listen_for_changes(UpdateSeq) end),
{ok, #state{changes_pid = Pid, update_seq = UpdateSeq}}.
diff --git a/src/mem3/src/mem3_sup.erl b/src/mem3/src/mem3_sup.erl
index 80b8ca3..0647447 100644
--- a/src/mem3/src/mem3_sup.erl
+++ b/src/mem3/src/mem3_sup.erl
@@ -20,6 +20,7 @@ start_link() ->
init(_Args) ->
Children = [
child(mem3_events),
+ child(mem3_dns),
child(mem3_nodes),
child(mem3_sync_nodes), % Order important?
child(mem3_sync),
--
To stop receiving notification emails like this one, please contact
"commits@couchdb.apache.org" <commits@couchdb.apache.org>.
|