Why is `net_kernel:hidden_connect_node/1` undocumented?

I’m using peer:start_link/1 to start a node, and I want to connect to it as a hidden node via shell. The net_kernel:hidden_connect_node/1 function does exactly what I want, but it’s undocumented. Why? Is there any other alternative?

There were some relevant discussions in the past:

Thanks, José!

It does not sound good to me. Is there a way to call peer:start_link/1 and pass the -hidden option to it?

A fully connected mesh is not an option for me. I need a “master” node connected to “slave” nodes, but “slave” nodes should not be connected.

My current implementation is something like this:

start(Name, Host, Port, Apps) when
    is_atom(Name), is_list(Host), is_integer(Port), is_list(Apps)
->
    {ok, Ref, Node} = peer:start_link(#{
        name => Name,
        host => Host,
        connection => Port
    }),
    ok = peer:call(Ref, code, add_paths, [code:get_path()]),
    [
        {ok, _} = peer:call(Ref, application, ensure_all_started, [App])
     || App <- Apps
    ],
    true = peer:call(Ref, erlang, set_cookie, [erlang:get_cookie()]),
    true = net_kernel:hidden_connect_node(Node),
    Ref.

It works as intended, but can I achieve this another way without the net_kernel:hidden_connect_node/1?

Any help is appreciated :slight_smile:

Ok, so I ended up starting all nodes via the terminal.

My goal is to have a structure like this:

foo * * master * * baz
           *
           *     
          bar

And not a mesh, like:

foo * * master * * baz
   *       *       *  
     *     *     *
       *  bar  *

And this is something I have ended up with:

  1. Start the slave nodes:
$ erl -sname foo@localhost -setcookie foo -connect_all false
$ erl -sname bar@localhost -setcookie bar -connect_all false
  1. Start and setup the master node:
$ erl -sname master@localhost -setcookie master
(master@localhost)1> erlang:set_cookie(foo@localhost, foo).
true
(master@localhost)2> net_kernel:connect_node(foo@localhost).
true
(master@localhost)3> erlang:set_cookie(bar@localhost, bar).
true
(master@localhost)4> net_kernel:connect_node(bar@localhost).
true
(master@localhost)5> nodes().
[foo@localhost,bar@localhost]
  1. Result in slave nodes:
(foo@localhost)1> nodes().
[master@localhost]
(bar@localhost)1> nodes().
[master@localhost]

The reason for keeping the slave nodes unconnected is security. I’ve no idea if this can be really secure since cookies intent is not security.

I would appreciate any good article, book, suggestion, video, or anything related to this topic.
I’m a newbie in distribution. It’s a challenging subject for me. Thanks!


Edit

I’ve just realized I can achieve the same result by using peer in the master node shell:

erl -sname master@localhost
Erlang/OTP 27 [erts-15.1] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [jit:ns]

Eshell V15.1 (press Ctrl+G to abort, type help(). for help)
(master@localhost)1> {ok, Foo, _} = peer:start_link(#{name => foo@localhost, args => ["-connect_all", "false"], connection => 0}).
{ok,<0.97.0>,foo@localhost}
(master@localhost)2> {ok, Bar, _} = peer:start_link(#{name => bar@localhost, args => ["-connect_all", "false"], connection => 0}).
{ok,<0.99.0>,bar@localhost}
(master@localhost)3> erlang:set_cookie(foo@localhost, foo).
true
(master@localhost)4> erlang:set_cookie(bar@localhost, bar).
true
(master@localhost)5> peer:call(Foo, erlang, set_cookie, [foo]).
true
(master@localhost)6> peer:call(Bar, erlang, set_cookie, [bar]).
true
(master@localhost)7> net_kernel:connect_node(foo@localhost).
true
(master@localhost)8> net_kernel:connect_node(bar@localhost).
true
(master@localhost)9> nodes().
[foo@localhost,bar@localhost]
(master@localhost)10> peer:call(Foo, erlang, nodes, []).
[master@localhost]
(master@localhost)11> peer:call(Bar, erlang, nodes, []).
[master@localhost]
1 Like

It seems that the Erlang distribution is not what I need in that case. I can always access the master node and all information about other nodes via RPC, so I’m considering moving to a gen_tcp interface. BTW, I’m still accepting suggestions :slight_smile:

Relevant sources:

Some time ago I created a MeshxNode package. In short it is a custom carrier protocol implementation using service mesh for transport and discovery. It would be possible to leverage for example Consul intentions to control communication between nodes. I didn’t update this for a long time, possibly it will not even work with current Consul version.

1 Like

Yes. In fact, you can start the peer node with any distribution option you like, or even with no distribution. You can also use it to test the distribution itself! Take a look at connection argument, specifically, standard_io control channel option.

With that option, you can still use peer:call to make RPC calls via control channel (not distribution).

It appears similar to structure created by this test case in the OTP codebase: otp/lib/kernel/test/pg_SUITE.erl at master · erlang/otp · GitHub

That’s exactly what standard_io was designed for. If you look at peer documentation, there is a Docker example that goes even further - it starts peer nodes in a separate container! Potentially, it could be a remote host just as well.

4 Likes

Thanks a lot! The example in the pg_SUITE is exactly what I was looking for. I don’t need net_kernel:hidden_connect_node/1 anymore.