summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJay Doane <jaydoane@apache.org>2019-02-12 11:27:13 -0800
committerJay Doane <jaydoane@apache.org>2019-02-12 11:27:13 -0800
commita6c1988c5db4993487ea627cc6009e1f5d51d367 (patch)
tree90a781dfbbd15c19ca1828637babbd23eb69c4fa
parentb46df8c8d3c96eadb07d540b82fcb992e6da2a82 (diff)
downloadcouchdb-a6c1988c5db4993487ea627cc6009e1f5d51d367.tar.gz
Sync admin password hashes at cluster setup finish
This ensures that admin password hashes are the same on all nodes when passwords are set directly on each node rather than through the coordinator node.
-rw-r--r--src/setup/src/setup.erl66
1 files changed, 66 insertions, 0 deletions
diff --git a/src/setup/src/setup.erl b/src/setup/src/setup.erl
index 3ae455f54..9437fbc07 100644
--- a/src/setup/src/setup.erl
+++ b/src/setup/src/setup.erl
@@ -198,9 +198,75 @@ setup_node(NewCredentials, NewBindAddress, NodeCount, Port) ->
finish_cluster(Options) ->
+ ok = wait_connected(),
+ ok = sync_admins(),
Dbs = proplists:get_value(ensure_dbs_exist, Options, cluster_system_dbs()),
finish_cluster_int(Dbs, has_cluster_system_dbs(Dbs)).
+
+wait_connected() ->
+ Nodes = other_nodes(),
+ Result = test_util:wait(fun() ->
+ case disconnected(Nodes) of
+ [] -> ok;
+ _ -> wait
+ end
+ end),
+ case Result of
+ timeout ->
+ Reason = "Cluster setup timed out waiting for nodes to connect",
+ throw({setup_error, Reason});
+ ok ->
+ ok
+ end.
+
+
+other_nodes() ->
+ mem3:nodes() -- [node()].
+
+
+disconnected(Nodes) ->
+ lists:filter(fun(Node) ->
+ case net_adm:ping(Node) of
+ pong -> false;
+ pang -> true
+ end
+ end, Nodes).
+
+
+sync_admins() ->
+ ok = lists:foreach(fun({User, Pass}) ->
+ sync_admin(User, Pass)
+ end, config:get("admins")).
+
+
+sync_admin(User, Pass) ->
+ {Results, Errors} = rpc:multicall(other_nodes(), config, set,
+ ["admins", User, Pass]),
+ case validate_multicall(Results, Errors) of
+ ok ->
+ ok;
+ error ->
+ log:error("~p sync_admin results ~p errors ~p",
+ [?MODULE, Results, Errors]),
+ Reason = "Cluster setup unable to sync admin passwords",
+ throw({setup_error, Reason})
+ end.
+
+
+validate_multicall(Results, Errors) ->
+ AllOk = lists:all(fun
+ (ok) -> true;
+ (_) -> false
+ end, Results),
+ case AllOk andalso Errors == [] of
+ true ->
+ ok;
+ false ->
+ error
+ end.
+
+
finish_cluster_int(_Dbs, true) ->
{error, cluster_finished};
finish_cluster_int(Dbs, false) ->