1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20-module(kernel_config).
21
22-behaviour(gen_server).
23
24%% External exports
25-export([start_link/0]).
26%% Internal exports
27-export([init/1, handle_info/2, terminate/2, send_timeout/2]).
28-export([handle_call/3, handle_cast/2, code_change/3]).
29
30%%%-----------------------------------------------------------------
31%%% This module implements a process that configures the kernel
32%%% application.
33%%% Its purpose is that in the init phase waits for other nodes at startup,
34%%% if specified.
35%%%-----------------------------------------------------------------
36start_link() -> gen_server:start_link(kernel_config, [], []).
37
38%%-----------------------------------------------------------------
39%% Callback functions from gen_server
40%%-----------------------------------------------------------------
41
42-spec init([]) -> {'ok', []} | {'stop', term()}.
43
44init([]) ->
45    process_flag(trap_exit, true),
46    case sync_nodes() of
47	ok ->
48	    case whereis(dist_ac) of
49		DAC when is_pid(DAC) ->
50		    DAC ! {go, self()},
51		    receive
52			dist_ac_took_control ->
53			    ok
54		    end;
55		_ ->
56		    ok
57	    end,
58	    {ok, []};
59	{error, Error} ->
60	    {stop, Error}
61    end.
62
63-spec handle_info(term(), State) -> {'noreply', State}.
64
65handle_info(_, State) ->
66    {noreply, State}.
67
68-spec terminate(term(), term()) -> 'ok'.
69
70terminate(_Reason, _State) ->
71    ok.
72
73-spec handle_call(term(), term(), State) -> {'reply', 'ok', State}.
74
75handle_call('__not_used', _From, State) ->
76    {reply, ok, State}.
77
78-spec handle_cast(term(), State) -> {'noreply', State}.
79
80handle_cast('__not_used', State) ->
81    {noreply, State}.
82
83-spec code_change(term(), State, term()) -> {'ok', State}.
84
85code_change(_OldVsn, State, _Extra) ->
86    {ok, State}.
87
88%%-----------------------------------------------------------------
89%% Internal functions
90%%-----------------------------------------------------------------
91sync_nodes() ->
92    case catch get_sync_data() of
93	{error, Reason} = Error ->
94	    error_logger:format("~tp", [Reason]),
95	    Error;
96	{infinity, MandatoryNodes, OptionalNodes} ->
97	    case wait_nodes(MandatoryNodes, OptionalNodes) of
98		ok ->
99%		    sync(),
100		    ok;
101		Error ->
102		    Error
103	    end;
104	{Timeout, MandatoryNodes, OptionalNodes} ->
105	    spawn_link(kernel_config, send_timeout, [Timeout, self()]),
106	    case wait_nodes(MandatoryNodes, OptionalNodes) of
107		ok ->
108%		    sync(),
109		    ok;
110		Error ->
111		    Error
112	    end;
113	undefined -> ok
114    end.
115
116send_timeout(Timeout, Pid) ->
117    receive
118    after Timeout -> Pid ! timeout
119    end.
120
121wait_nodes(Mandatory, Optional) ->
122    ok = net_kernel:monitor_nodes(true),
123    lists:foreach(fun(Node) ->
124		     case net_adm:ping(Node) of
125			 pong -> self() ! {nodeup, Node};
126			 _ -> ok
127		     end
128		  end,
129		  Mandatory ++ Optional),
130    R = rec_nodes(Mandatory, Optional),
131    ok = net_kernel:monitor_nodes(false),
132    R.
133
134rec_nodes([], []) -> ok;
135rec_nodes(Mandatory, Optional) ->
136    receive
137	{nodeup, Node} -> check_up(Node, Mandatory, Optional);
138	timeout when Mandatory =:= [] -> ok;
139	timeout -> {error, {mandatory_nodes_down, Mandatory}}
140    end.
141
142check_up(Node, Mandatory, Optional) ->
143    case lists:member(Node, Mandatory) of
144	true ->
145	    rec_nodes(lists:delete(Node, Mandatory), Optional);
146	false ->
147	    case lists:member(Node, Optional) of
148		true ->
149		    rec_nodes(Mandatory, lists:delete(Node, Optional));
150		false ->
151		    rec_nodes(Mandatory, Optional)
152	    end
153    end.
154
155%% Syncs standard servers
156%sync() ->
157%    global:sync().
158
159get_sync_data() ->
160    Timeout = get_sync_timeout(),
161    MandatoryNodes = get_sync_mandatory_nodes(),
162    OptionalNodes = get_sync_optional_nodes(),
163    {Timeout, MandatoryNodes, OptionalNodes}.
164
165get_sync_timeout() ->
166    case application:get_env(sync_nodes_timeout) of
167	{ok, Timeout} when is_integer(Timeout), Timeout > 0 -> Timeout;
168	{ok, infinity}  -> infinity;
169	undefined -> throw(undefined);
170	{ok, Else} -> throw({error, {badopt, {sync_nodes_timeout, Else}}})
171    end.
172
173get_sync_mandatory_nodes() ->
174    case application:get_env(sync_nodes_mandatory) of
175	{ok, Nodes} when is_list(Nodes) -> Nodes;
176	undefined -> [];
177	{ok, Else} -> throw({error, {badopt, {sync_nodes_mandatory, Else}}})
178    end.
179
180get_sync_optional_nodes() ->
181    case application:get_env(sync_nodes_optional) of
182	{ok, Nodes} when is_list(Nodes) -> Nodes;
183	undefined -> [];
184	{ok, Else} -> throw({error, {badopt, {sync_nodes_optional, Else}}})
185    end.
186
187