[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