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 <[email protected]> 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 "[email protected]" <[email protected]>.
