Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use ssh_connection:exec in Erlang?

Tags:

erlang

This is an interesting situation, focused on the behavior of erlang ssh modules. I had spent a few hours troubleshooting a problem that turned out to reveal that the Erlang ssh_connection *exec/4* function operates asynchronously.

If you issue the ssh_connection:exec/4 function to run a script that takes several seconds to complete, and then in your erlang program you close the ssh connection, the script execution will terminate. My expectation was that the ssh_connection:exec would be synchronous rather than asynchronous.

Because the time to complete the remote script invoked by ssh_connection:exec is unknown, I chose to not issue the closure ssh:close(). I would like to understand the consequences of that:

  • Will the gc clear it at some point ?
  • Will it stay open for good during the whole node existence ?
  • Is there a way to make the ssh_connection:exec synchronous, as I would believe it should be.

Here is an example of the test erl program that I used to verify this issue. As a script you can run a simple sleep 10 (sleep 10 seconds) to emulate a slow running program.

-module(testssh).
-export([test/5]).

test (ServerName, Port, Command, User, Password) ->

    crypto:start(),
    ssh:start(),
    {ok, SshConnectionRef}                  = ssh:connect(ServerName, Port, [ {user, User}, {password, Password} , {silently_accept_hosts, true} ], 60000  ),
    {ok, SshConnectionChannelRef}           = ssh_connection:session_channel(SshConnectionRef, 60000),
    Status                                  = ssh_connection:exec(SshConnectionRef, SshConnectionChannelRef, Command, 60000),
    ssh:close(SshConnectionRef).

Remote script:

#!/bin/sh
sleep 10
like image 582
gextra Avatar asked Oct 03 '22 22:10

gextra


1 Answers

I never had to use the ssh application myself, but you should be reading something wrong, it is clear in the doc that the result will be delivered as messages to the caller:

[...] the result will be several messages according to the following pattern. Note that the last message will be a channel close message, as the exec request is a one time execution that closes the channel when it is done[...]

See http://www.erlang.org/doc/man/ssh_connection.html#exec-4

So after you call ssh_connection:exec/4 , test with a loop like this:

wait_for_response(ConnectionRef) ->
    receive
            {ssh_cm, ConnectionRef, Msg} ->
                    case Msg of
                            {closed, _ChannelId} ->
                                    io:format("Done");
                            _ ->
                                    io:format("Got: ~p", [Msg]),
                                    wait_for_response(ConnectionRef)
                    end
    end.

You should receive the command output, and other ssh messages, and finally a 'closed' message that is your signal that the ssh command has properly finished.

like image 129
ppolv Avatar answered Oct 07 '22 20:10

ppolv