瀏覽代碼

Extract dist config handling, support {dist, ...}

This commit moves the handling of distribution config and starting out
of rebar_prv_shell and into rebar_dist_utils. The module is able to
handle standard config options and boot a distributed node mode. This
could be used in plugins (once it is exposed) and other providers like
CT.

Configuration is also expanded so that options like:

    {dist, [{sname, atom()}, {name, atom()}, {setcookie, term()}]}

can be used and will be handled as a default. The config handler
supports similar terms from the command line being parsed in if the
calling provider supports them.

A test suite is added for configuration handling.
pull/1132/head
Fred Hebert 9 年之前
父節點
當前提交
7a1b59015f
共有 3 個文件被更改,包括 165 次插入27 次删除
  1. +89
    -0
      src/rebar_dist_utils.erl
  2. +2
    -27
      src/rebar_prv_shell.erl
  3. +74
    -0
      test/rebar_dist_utils_SUITE.erl

+ 89
- 0
src/rebar_dist_utils.erl 查看文件

@ -0,0 +1,89 @@
%%% Common functions to boot/stop distributed setups for
%%% the rebar3 script.
-module(rebar_dist_utils).
-export([either/3, short/2, long/2, find_options/1]).
-include("rebar.hrl").
%%%%%%%%%%%%%%%%%%
%%% PUBLIC API %%%
%%%%%%%%%%%%%%%%%%
-spec either(Name::atom(), SName::atom(), Opts::[{setcookie,term()}]) -> atom().
either(undefined, undefined, _) ->
'nonode@nohost';
either(Name, undefined, Opts) ->
long(Name, Opts),
node();
either(undefined, SName, Opts) ->
short(SName, Opts),
node();
either(_, _, _) ->
?ABORT("Cannot have both short and long node names defined", []).
short(Name, Opts) ->
start(Name, shortnames, Opts).
long(Name, Opts) ->
start(Name, longnames, Opts).
-spec find_options(rebar_state:state()) -> {Long, Short, Opts} when
Long :: atom(),
Short :: atom(),
Opts :: [{setcookie,term()}].
find_options(State) ->
{Long, Short} = find_name_options(State),
case find_cookie_option(State) of
nocookie ->
{Long, Short, []};
Cookie ->
{Long, Short, [{setcookie, Cookie}]}
end.
%%%%%%%%%%%%%%%
%%% PRIVATE %%%
%%%%%%%%%%%%%%%
start(Name, Type, Opts) ->
check_epmd(net_kernel:start([Name, Type])),
setup_cookie(Opts).
check_epmd({error,{{shutdown, {_,net_kernel,{'EXIT',nodistribution}}},_}}) ->
?ERROR("Erlang Distribution failed, falling back to nonode@nohost. "
"Verify that epmd is running and try again.",[]);
check_epmd(_) ->
ok.
setup_cookie(Opts) ->
case {node(), proplists:get_value(setcookie, Opts, nocookie)} of
{'nonode@nohost', _} -> nocookie;
{_, nocookie} -> nocookie;
{Node, Name} -> erlang:set_cookie(Node, Name)
end.
find_name_options(State) ->
{Opts, _} = rebar_state:command_parsed_args(State),
%% First try the CLI
case {proplists:get_value(name, Opts), proplists:get_value(sname, Opts)} of
{undefined, undefined} ->
%% Else try the config file
DistOpts = rebar_state:get(State, dist, []),
%% Pick the first one seen to support profile merges
find_first_name(DistOpts);
Res ->
Res
end.
find_first_name([]) -> {undefined, undefined};
find_first_name([{sname,Val}|_]) -> {undefined, Val};
find_first_name([{name,Val}|_]) -> {Val, undefined};
find_first_name([_|Opts]) -> find_first_name(Opts).
find_cookie_option(State) ->
{Opts, _} = rebar_state:command_parsed_args(State),
%% First try the CLI
case proplists:get_value(setcookie, Opts) of
undefined ->
%% Else try the config file
DistOpts = rebar_state:get(State, dist, []),
proplists:get_value(setcookie, DistOpts, nocookie);
Res ->
Res
end.

+ 2
- 27
src/rebar_prv_shell.erl 查看文件

@ -269,33 +269,8 @@ simulate_proc_lib() ->
put('$initial_call', {rebar_agent, init, 1}).
setup_name(State) ->
{Opts, _} = rebar_state:command_parsed_args(State),
case {proplists:get_value(name, Opts), proplists:get_value(sname, Opts)} of
{undefined, undefined} ->
ok;
{Name, undefined} ->
check_epmd(net_kernel:start([Name, longnames])),
setup_cookie(Opts);
{undefined, SName} ->
check_epmd(net_kernel:start([SName, shortnames])),
setup_cookie(Opts);
{_, _} ->
?ABORT("Cannot have both short and long node names defined", [])
end.
check_epmd({error,{{shutdown, {_,net_kernel,{'EXIT',nodistribution}}},_}}) ->
?ERROR("Erlang Distribution failed, falling back to nonode@nohost. "
"Verify that epmd is running and try again.",[]);
check_epmd(_) ->
ok.
setup_cookie(Opts) ->
case {node(), proplists:get_value(setcookie, Opts, nocookie)} of
{'nonode@nohost', _} -> nocookie;
{_, nocookie} -> nocookie;
{Node, Name} -> erlang:set_cookie(Node, Name)
end.
{Long, Short, Opts} = rebar_dist_utils:find_options(State),
rebar_dist_utils:either(Long, Short, Opts).
find_apps_to_boot(State) ->
%% Try the shell_apps option

+ 74
- 0
test/rebar_dist_utils_SUITE.erl 查看文件

@ -0,0 +1,74 @@
%%% This suite currently only tests for options parsing since we do
%%% not know if epmd will be running to actually boot nodes.
-module(rebar_dist_utils_SUITE).
-include_lib("common_test/include/ct.hrl").
-include_lib("eunit/include/eunit.hrl").
-compile(export_all).
all() -> [from_config, from_cli, overlap, from_config_profile].
init_per_testcase(_, Config0) ->
Config = rebar_test_utils:init_rebar_state(Config0),
AppDir = ?config(apps, Config),
Name = rebar_test_utils:create_random_name("app_"),
Vsn = rebar_test_utils:create_random_vsn(),
rebar_test_utils:create_app(filename:join([AppDir,"apps",Name]), Name, Vsn, [kernel, stdlib]),
Config.
end_per_testcase(_, _) ->
ok.
from_config(Config) ->
ShortConfig = [{dist, [{sname, 'a@localhost'}, {setcookie, abc}]}],
LongConfig = [{dist, [{name, 'a@localhost.x'}, {setcookie, abc}]}],
BothConfig = [{dist, [{sname, 'a@localhost'}, {name, 'a@localhost.x'}, {setcookie,abc}]}],
NoConfig = [],
CookieConfig = [{dist, [{setcookie, def}]}],
NoCookie = [{dist, [{sname, 'a@localhost'}]}],
{ok, State0} = rebar_test_utils:run_and_check(Config, ShortConfig, ["version"], return),
{undefined, 'a@localhost', [{setcookie, abc}]} = rebar_dist_utils:find_options(State0),
{ok, State1} = rebar_test_utils:run_and_check(Config, LongConfig, ["version"], return),
{'a@localhost.x', undefined, [{setcookie, abc}]} = rebar_dist_utils:find_options(State1),
%% only support the first name found, side-effect of wanting profile support
{ok, State2} = rebar_test_utils:run_and_check(Config, BothConfig, ["version"], return),
{undefined, 'a@localhost', [{setcookie, abc}]} = rebar_dist_utils:find_options(State2),
{ok, State3} = rebar_test_utils:run_and_check(Config, NoConfig, ["version"], return),
{undefined, undefined, []} = rebar_dist_utils:find_options(State3),
{ok, State4} = rebar_test_utils:run_and_check(Config, CookieConfig, ["version"], return),
{undefined, undefined, [{setcookie, def}]} = rebar_dist_utils:find_options(State4),
{ok, State5} = rebar_test_utils:run_and_check(Config, NoCookie, ["version"], return),
{undefined, 'a@localhost', []} = rebar_dist_utils:find_options(State5),
ok.
from_cli(Config) ->
{ok, State0} = rebar_test_utils:run_and_check(Config, [], ["version"], return),
{undefined, undefined, []} = rebar_dist_utils:find_options(State0),
State1 = rebar_state:command_parsed_args(State0, {[{sname, 'a@localhost'}, {setcookie,abc}], []}),
{undefined, 'a@localhost', [{setcookie, abc}]} = rebar_dist_utils:find_options(State1),
State2 = rebar_state:command_parsed_args(State0, {[{name, 'a@localhost.x'}, {setcookie,abc}], []}),
{'a@localhost.x', undefined, [{setcookie, abc}]} = rebar_dist_utils:find_options(State2),
State3 = rebar_state:command_parsed_args(State0, {[{sname, 'a@localhost'}, {name, 'a@localhost.x'}, {setcookie,abc}], []}),
{'a@localhost.x', 'a@localhost', [{setcookie, abc}]} = rebar_dist_utils:find_options(State3),
State4 = rebar_state:command_parsed_args(State0, {[{setcookie,def}], []}),
{undefined, undefined, [{setcookie, def}]} = rebar_dist_utils:find_options(State4),
State5 = rebar_state:command_parsed_args(State0, {[{sname, 'a@localhost'}], []}),
{undefined, 'a@localhost', []} = rebar_dist_utils:find_options(State5),
ok.
overlap(Config) ->
%% Make sure that CLI config takes over rebar config without clash for names, though
%% cookies can pass through
RebarConfig = [{dist, [{sname, 'a@localhost'}, {setcookie, abc}]}],
{ok, State0} = rebar_test_utils:run_and_check(Config, RebarConfig, ["version"], return),
State1 = rebar_state:command_parsed_args(State0, {[{name, 'b@localhost.x'}], []}),
{'b@localhost.x', undefined, [{setcookie, abc}]} = rebar_dist_utils:find_options(State1),
ok.
from_config_profile(Config) ->
%% running as a profile does not create name clashes
RebarConfig = [{dist, [{sname, 'a@localhost'}, {setcookie, abc}]},
{profiles, [ {fake, [{dist, [{name, 'a@localhost.x'}]}]} ]}],
{ok, State0} = rebar_test_utils:run_and_check(Config, RebarConfig, ["as","fake","version"], return),
{'a@localhost.x', undefined, [{setcookie, abc}]} = rebar_dist_utils:find_options(State0),
ok.

Loading…
取消
儲存