[erlang-questions] SSH SCP

Siraaj Khandkar siraaj@REDACTED
Tue Jul 17 09:46:59 CEST 2012


On Jul 16, 2012, at 3:39 PM, gabre@REDACTED wrote:

> Hello,
> 
> I d like to ask about the SSH module found in OTP. I would like to use
> the SCP command (which uses ssh) via Erlang (SSH module). Is there
> anybody, who can explain me, how to do it? I have googled and searched
> million times, but nothing... (I have also tried it using os:cmd/1 and a
> seld-made shell loop)


I haven't gotten around to file transfers (with OTP ssh app) yet, but I
did manage to mostly figure-out the basics of using the SSH app, and can
give you a jump start.

For the simplest example of doing something useful, lets say we want a
an escript that sort-of mimics an ssh command. First, make sure you have
an SSH directory (~/.ssh) and a pub-priv key pair (~/.ssh/id_dsa and
~/.ssh/id_dsa.pub) that is NOT password protected. This last part is
important, because at this time the ssh app does not yet support
password-protected keys [1]. After you have the key pair, the simplest
implementation could look something like this:


    #! /usr/bin/env escript

    %%% ----------------------------------------------------------------------
    %%% file: ssh.erl
    %%% ----------------------------------------------------------------------


    main([User, Address, Port, Command]) ->
        ok = crypto:start(),
        ok = ssh:start(),

        Timeout = 5000,
        SSHDirectory = filename:join(os:getenv("HOME"), ".ssh"),

        ConnectOptions = [
            {user, User},
            {connect_timeout, Timeout},
            {silently_accept_hosts, true},
            {user_interaction, true},
            {user_dir, SSHDirectory}
        ],

        case ssh:connect(Address, list_to_integer(Port), ConnectOptions) of
            {ok, ConnRef} ->
                case ssh_connection:session_channel(ConnRef, Timeout) of
                    {ok, ChannId} ->
                        ssh_connection:exec(ConnRef, ChannId, Command, Timeout),
                        Data = collect_data(),
                        io:format("~s~n", [Data]);

                    {error, Reason} ->
                        io:format("~p~n", [Reason])
                end;
            {error, Reason} ->
                io:format("~p~n", [Reason])
        end;

    main(_) ->
        io:format("USAGE: ssh.erl <user> <address> <port> <command>~n").


    collect_data() -> collect_data([]).
    collect_data(Data) ->
        receive
            {ssh_cm, _, {data, _, _, Datum}} ->
                collect_data([Datum | Data]);

            {ssh_cm, _, {closed, _}} ->
                lists:reverse(Data);

            {ssh_cm, _} ->
                collect_data(Data)
        end.


For a more extended example of the use of the above code, see my Cluster
Commander project [2], particularly commander_worker_otp.erl module. I
also took advantage of OS's ssh/scp commands (as an alternative to OTP
ssh and as the only, for now, way to do scp), see
commander_worker_os.erl module and os_cmd/1 function in
commander_lib.erl module.

The above uses ssh_connection:exec/4 to just send a command string to
the remote host and receive the resulting data, but, for more
interesting uses, you can also use ssh_connection:send/3-5 and push any
data you want to the remote host (assuming it knows how to interpret
it).

For a more interesting example, see Kenji Rikitake's sshrpc [3] [4] and
my (uber-early and half-baked) attempts at implementing the ssh_channel
behavior for my needs [5].


[1] - http://erlang.org/pipermail/erlang-questions/2010-April/050637.html
[2] - https://github.com/ibnfirnas/cluster-commander
[3] - https://github.com/jj1bdx/sshrpc
[4] - http://www.erlang-factory.com/conference/SFBay2010/speakers/kenjirikitake
[5] - https://github.com/ibnfirnas/data-mill


-- 
Siraaj Khandkar
.o.
..o
ooo





More information about the erlang-questions mailing list