在节点引导之前取消设置所有路径

时间:2015-07-04 16:34:00

标签: erlang

TLDR ; 当启动erlang节点(仅对实例使用erl命令)时,如何强制它不使用本地OTP库并使code:get_path()为空?

原理。

我想触摸erl_boot_server。不要做某些事情,只是玩。我已经构建了样本版本,并希望通过网络加载它。就是这样。

[vkovalev@t30nix foobar]$ tree -L 2
.
|-- bin
|   |-- foobar
|   |-- foobar-0.0.0+build.1.ref307ae38
|   |-- install_upgrade.escript
|   |-- nodetool
|   `-- start_clean.boot
|-- erts-6.1
|   |-- bin
|   |-- doc
|   |-- include
|   |-- lib
|   |-- man
|   `-- src
|-- lib
|   |-- foobar-0.1.0
|   |-- kernel-3.0.1
|   |-- sasl-2.4
|   `-- stdlib-2.1
`-- releases
    |-- 0.0.0+build.1.ref307ae38
    |-- RELEASES
    `-- start_erl.data

首先我启动启动节点。

[vkovalev@t30nix foobar]$ erl -sname boot -pa lib/*/ebin -pa releases/0.0.0+build.1.ref307ae38/ -s erl_boot_server start localhost

(boot@t30nix)1> {ok, _, _} = erl_prim_loader:get_file("foobar.boot").
(boot@t30nix)2> {ok, _, _} = erl_prim_loader:get_file("foobar_app.beam").

如你所见,一切都没问题。然后我启动从节点:

[vkovalev@t30nix ~]$ erl -sname slave -loader inet -hosts 127.0.0.1  -boot foobar
{"init terminating in do_boot",{'cannot get bootfile','foobar.boot'}}

Crash dump was written to: erl_crash.dump
init terminating in do_boot ()

我挖到erl_prim_loader并找到了that stuff。一个子句在Paths为空时起作用(它只是将请求的文件名转发到引导服务器),另一个子句在Paths非空时起作用。在这种情况下(我想知道为什么)prim loader cripples请求文件名和它自己的(clientside)路径,然后让SERVER提供这个路径。根据我的理解,这是非常奇怪的事情,但没关系。然后我检查了从节点上的code:get_path(),是的,它有本地otp安装的路径。

所以,回到主题。如何强制slave节点不使用任何本地OTP安装(如果它已经存在)?

UPD:添加了更多调查结果。

  1. 第一件事 - https://github.com/erlang/otp/blob/maint/erts/preloaded/src/erl_prim_loader.erl#L669。 erl_prim_loader(在inet模式下)对某些(我不清楚)原因尝试 使用本地(客户端)路径削弱任何请求的模块。

  2. 似乎无法在slave节点上强制加载程序来保留它 路径为空:https://github.com/erlang/otp/blob/maint/erts/preloaded/src/init.erl#L697

  3. 我的bootscript中的路径看起来像 {path,[“$ ROOT / lib / kernel-4.0 / ebin”,“$ ROOT / lib / stdlib-2.5 / ebin”]},所以 看来,如果我加载了靴子,无论如何,我都无法启动 系统吧。

  4. 发生了什么事? erlang网络启动功能是否已损坏?或者只是我的 脑子吗?我怎样才能使节点成功进行网络启动?

3 个答案:

答案 0 :(得分:0)

你认为奴隶类型的节点是由"奴隶"?

命名的

来自项目tsung的以下代码,文件名为" ts_os_mon_erlang.erl"。

start_beam(Host) ->
    Args = ts_utils:erl_system_args(),
    ?LOGF("Starting os_mon beam on host ~p ~n", [Host], ?NOTICE),
    ?LOGF("~p Args: ~p~n", [Host, Args], ?DEB),
    slave:start(list_to_atom(Host), ?NODE, Args).

此外,从模块限制如下:

Slave nodes on other hosts than the current one are started with the program rsh. The user must be allowed to rsh to the remote hosts without being prompted for a password. This can be arranged in a number of ways (refer to the rsh documentation for details). A slave node started on the same host as the master inherits certain environment values from the master, such as the current directory and the environment variables. For what can be assumed about the environment when a slave is started on another host, read the documentation for the rsh program.

An alternative to the rsh program can be specified on the command line to erl as follows: -rsh Program.

The slave node should use the same file system at the master. At least, Erlang/OTP should be installed in the same place on both computers and the same version of Erlang should be used.

如果你想用不同的路径启动一个节点,我认为你可以通过具有不同环境变量的脚本来实现,对于主节点而不是从节点。

答案 1 :(得分:0)

我认为螺纹钢项目可以帮助达到类似的目的。它包括如何操纵路径:

来自rebar_core.erl档案:     process_dir1(Dir,Command,DirSet,Config,CurrentCodePath,                  {DirModules,ModuleSetFile}) - >         Config0 = rebar_config:set(Config,current_command,Command),         %%获取"任何目录"的模块列表。这是一个包罗万象的清单         除了相关模块之外还处理的模块的%%         %%具有此目录类型。处理这些any_dir模块         %% FIRST。         {ok,AnyDirModules} = application:get_env(rebar,any_dir_modules),

    Modules = AnyDirModules ++ DirModules,

    %% Invoke 'preprocess' on the modules -- this yields a list of other
    %% directories that should be processed _before_ the current one.
    {Config1, Predirs} = acc_modules(Modules, preprocess, Config0,
                                     ModuleSetFile),

    %% Remember associated pre-dirs (used for plugin lookup)
    PredirsAssoc = remember_cwd_predirs(Dir, Predirs),

    %% Get the list of plug-in modules from rebar.config. These
    %% modules may participate in preprocess and postprocess.
    {ok, PluginModules} = plugin_modules(Config1, PredirsAssoc),

    {Config2, PluginPredirs} = acc_modules(PluginModules, preprocess,
                                           Config1, ModuleSetFile),

    AllPredirs = Predirs ++ PluginPredirs,

    ?DEBUG("Predirs: ~p\n", [AllPredirs]),
    {Config3, DirSet2} = process_each(AllPredirs, Command, Config2,
                                      ModuleSetFile, DirSet),

    %% Make sure the CWD is reset properly; processing the dirs may have
    %% caused it to change
    ok = file:set_cwd(Dir),

    %% Check that this directory is not on the skip list
    Config7 = case rebar_config:is_skip_dir(Config3, Dir) of
                  true ->
                      %% Do not execute the command on the directory, as some
                      %% module has requested a skip on it.
                      ?INFO("Skipping ~s in ~s\n", [Command, Dir]),
                      Config3;

                  false ->
                      %% Check for and get command specific environments
                      {Config4, Env} = setup_envs(Config3, Modules),

                      %% Execute any before_command plugins on this directory
                      Config5 = execute_pre(Command, PluginModules,
                                            Config4, ModuleSetFile, Env),

                      %% Execute the current command on this directory
                      Config6 = execute(Command, Modules ++ PluginModules,
                                        Config5, ModuleSetFile, Env),

                      %% Execute any after_command plugins on this directory
                      execute_post(Command, PluginModules,
                                   Config6, ModuleSetFile, Env)
              end,

    %% Mark the current directory as processed
    DirSet3 = sets:add_element(Dir, DirSet2),

    %% Invoke 'postprocess' on the modules. This yields a list of other
    %% directories that should be processed _after_ the current one.
    {Config8, Postdirs} = acc_modules(Modules ++ PluginModules, postprocess,
                                      Config7, ModuleSetFile),
    ?DEBUG("Postdirs: ~p\n", [Postdirs]),
    Res = process_each(Postdirs, Command, Config8,
                       ModuleSetFile, DirSet3),

    %% Make sure the CWD is reset properly; processing the dirs may have
    %% caused it to change
    ok = file:set_cwd(Dir),

    %% Once we're all done processing, reset the code path to whatever
    %% the parent initialized it to
    restore_code_path(CurrentCodePath),

    %% Return the updated {config, dirset} as result
    Res.

restore_code_path(no_change) ->
    ok;
restore_code_path({added, Paths}) ->
    %% Verify that all of the paths still exist -- some dynamically
    %% added paths can get blown away during clean.
    [code:del_path(F) || F <- Paths, erl_prim_loader_is_file(F)],
    ok.

erl_prim_loader_is_file(File) ->
    erl_prim_loader:read_file_info(File) =/= error.

答案 2 :(得分:0)

确保使用-setcookie选项。来自erl -man erl页面:

  

-loader Loader:

     

指定erl_prim_loader使用的方法              将Erlang模块加载到系统中。看到              erl_prim_loader(3)。支持两种Loader方法,              efile和inet。 efile表示使用本地文件              系统,这是默认值。 inet意味着使用启动              另一台机器上的服务器,-id,-hosts和              -setcookie标志也必须指定。如果装载机              是另一回事,用户提供了Loader端口              程序启动。