Beefy Boxes and Bandwidth Generously Provided by pair Networks
more useful options
 
PerlMonks  

Simple SSH based chat client

by techman2006 (Beadle)
on Sep 23, 2014 at 18:56 UTC ( [id://1101698]=perlquestion: print w/replies, xml ) Need Help??

techman2006 has asked for the wisdom of the Perl Monks concerning the following question:

I have a some device which can communicate over Serial ports. So to make things easy we have switch which can send Serial data over IP. Now to connect to this switch we need to use SSH and then we can fire a set of commands to perform some operations.

Now I am looking a way to automate these task as I have a around 8 such devices on which I need to send some common commands and some specific command (may be present in a file).

Also I am looking a way through which I can dump what is being output over the terminal in a file so that if later we want to take a look we can do so.

So how can we write a simple chat client which can send commands over SSH (you can think of hyper terminal command send to reset the device etc) and get the results and other output back. Any thoughts will be a great help.

Below is the code which I am able to do till now

#!/usr/bin/perl if( ! defined $ARGV[0] ) { print "Usage: ssh.pl <host> <port> [ <username> [ <password> ] + ]\n"; exit; } my ($host, $port, $username, $password) = @ARGV; $username = $ENV{USER} if $username eq ""; use Expect; use IO::Pty; my $spawn = new Expect; $spawn->raw_pty(1); # This gets the size of your terminal window $spawn->slave->clone_winsize_from(\*STDIN); my $PROMPT; # This function traps WINCH signals and passes them on sub winch { my $signame = shift; my $pid = $spawn->pid; $shucks++; print "count $shucks,pid $pid, SIG$signame\n"; $spawn->slave->clone_winsize_from(\*STDIN); kill WINCH => $spawn->pid if $spawn->pid; } $SIG{WINCH} = \&winch; # best strategy #$Expect::Exp_Internal = 1; #$Expect::Log_Stdout = 0; $spawn=Expect->spawn("ssh $username\@$host -p $port"); # log everything if you want $spawn->log_file("/tmp/autossh.log.$$"); my $PROMPT = '[\]\$\>\#]\s$'; my $ret = $spawn->expect(10, [ qr/\(yes\/no\)\?\s*$/ => sub { $spawn->send("yes\n"); exp_co +ntinue; } ], [ qr/assword:\s*$/ => sub { $spawn->send("$password\n") i +f defined $password; } ], [ qr/ogin:\s*$/ => sub { $spawn->send("$username\n"); +exp_continue; } ], [ qr/REMOTE HOST IDEN/ => sub { print "FIX: .ssh/known_hosts\n"; +exp_continue; } ], [ qr/$PROMPT/ => sub { $spawn->send("echo Now try window + resizing\n"); } ], [ qr/You are now master for the port\s*$/ => sub { $spawn->send("$ +cmd\n"); exp_continue; } ], ); $spawn->send("$cmd\r"); # Hand over control # Destroy the expect object $spawn->soft_close();

Sample session is given below

# perl ssh.pl <host name> <port> <username> <password> Password: Authentication successful. Starting DPA for port 1 Authentication successful. Escape Sequence is: Control-] You are now master for the port.

Now once I have You are now master for the port. I need to send some commands but I am not able to do so. So any thoughts how to fix this script.

Replies are listed 'Best First'.
Re: Simple SSH based chat client
by NetWallah (Canon) on Sep 23, 2014 at 19:32 UTC
Re: Simple SSH based chat client
by thanos1983 (Parson) on Sep 23, 2014 at 23:18 UTC

    Hello techman2006,

    Now to connect to this switch we need to use SSH and then we can fire a set of commands to perform some operations.

    Please provide us with more information, what commands you want to execute, do you require root permission etc.

    Recently there was similar question to yours Net::SSH2 to capture multiple commands on remote system where I am sure that you can find the answer. I have posted an answer exactly on what you want on this question.

    Update: Based on the answer given by NetWallah about parallel ssh, I remembered that I read somewhere for a module in Perl, while I was trying to complete my task. Here it is Net::OpenSSH::Parallel, search of the web there are tones of modules with ssh that can do your task. I chosen to use Net::OpenSSH because I needed to execute root commands, in this case it was perfect to me.

    Update 2: When I had trouble with the same task as you, I created a question Best module to execute administrator commands on external operating systems (Linux) at which you can find 3 different working answers to your problem with multiple devices.

    Seeking for Perl wisdom...on the process of learning...not there...yet!
      Now to connect to this switch we need to use SSH and then we can fire a set of commands to perform some operations. Please provide us with more information, what commands you want to execute, do you require root permission etc.

      These are very specific commands which these device can understand. Basically you can think of SMTP or IMAP session which client perform to server.

      So in case of SMTP chat session we send a particular command and based on that server can send some response. Again we send more commands and hence forth.

      So the task I am working right now is like automating these command to the terminal and then let the script keep running.

        Show us a sample session.
Re: Simple SSH based chat client
by Anonymous Monk on Sep 23, 2014 at 19:09 UTC
    As long as this isn't Windows, perhaps Net::OpenSSH combined with Expect? (Note the former includes a section in the doc on how to work with the latter.)
Re: Simple SSH based chat client
by thanos1983 (Parson) on Sep 24, 2014 at 14:52 UTC

    Hello again techman2006,

    Now I am looking a way to automate these task as I have a around 8 such devices on which I need to send some common commands and some specific command (may be present in a file).

    From my point of view and based on your sample code, I do not see your automation.

    # perl ssh.pl <host name> <port> <username> <password>

    You are probing a single device per time, instead of 8.

    I have posted several links on my previous reply, did you take a look on them?

    I think a solution to your problem could be much simpler, automated, easier and cleaner if you do something like that:

    Sample of code from Best module to execute administrator commands on external operating systems (Linux).

    Final Update 2 with better answer and output sample:

    So with no further delays this is the code for multiple devices. For sample purposes the code runs on my localhost.

    Configuration file (conf.ini)

    Seeking for Perl wisdom...on the process of learning...not there...yet!
Re: Simple SSH based chat client
by thanos1983 (Parson) on Sep 27, 2014 at 21:25 UTC

    Hello again techman2006,

    I was thinking about your question and I think I did not answer it correctly before. So I finally got some time today and I came up with this answer which is what I think you expect to see.

    I am reading and printing the written file on the terminal, so you can remove this part. I just used it for demonstration purposes.

    Working code, and output printed.

    #!/usr/bin/perl use Expect; use strict; use warnings; use Data::Dumper; use Net::OpenSSH; use Config::IniFiles; use Fcntl qw(:flock); $| = 1; # To see the complete debuging process #$Net::OpenSSH::debug = ~0; my $path = 'conf.ini'; my $timeout = 20; my $debug = 0; sub devices { open my $fh , '<' , "".$path."" or die "Could not open file: ".$path." - $!\n"; flock($fh, LOCK_SH) or die "Could not lock '".$fh."' - $!\n"; tie my %ini, 'Config::IniFiles', ( -file => "".$path."" ) or die "Error: IniFiles->new: @Config::IniFiles::errors"; close ($fh) or die "Could not close '".$fh."' - $!\n"; my @keys = keys (%ini); my %data = (); my %final = (); foreach my $hash (@keys) { %data = clk_sync( $ini{$hash}{host}, $ini{$hash}{user}, $ini{$hash}{psw}, $ini{$hash}{port}, $hash ); @final{keys %data} = values %data; } return %final; } # end sub complex my %results = devices(); print Dumper(\%results); sub clk_sync { # alternative of shift my ($host,$user,$passwd,$port,$device) = (@_); my $host = shift; my $user = shift; my $passwd = shift; my $port = shift; my $device = shift; my %opts = ( passwd => $passwd, port => $port, user => $user ); my $ssh = Net::OpenSSH->new( $host, %opts ); $ssh->error and die "Couldn't establish SSH connection: ". $ssh->error; my @commands = ( "ls /tmp" , "vmstat" ); foreach my $command ( @commands ) { my ($rout, $pid) = $ssh->pipe_out( $command ) or die "pipe_out method failed: " . $ssh->error; open my $write, ">>", "sample.txt" or die $!; print $write "" . $device . " Command executed: " . $command . "\n +"; while (<$rout>) { print $write $_; } print $write "\n"; close $rout; close $write; } # Not needed just for demonstration purposes open my $read, "<", "sample.txt" or die $!; while (my $row = <$read>) { chomp $row; print "$row\n"; } close $read; my %hash_out = ( $device => [ @commands ] ); return %hash_out; } __END__ DEVICE 1 Command executed: ls /tmp foo.txt orbit-tiny qtsingleapp-Viber-0-3e8 qtsingleapp-Viber-0-3e8-lockfile ssh-QEhD246wugPL unity_support_test.0 DEVICE 1 Command executed: vmstat procs -----------memory---------- ---swap-- -----io---- -system-- ---- +--cpu----- r b swpd free buff cache si so bi bo in cs us s +y id wa st 5 0 152888 584588 22596 1091568 1 8 83 125 771 491 40 + 6 53 1 0 DEVICE 1 Command executed: ls /tmp foo.txt orbit-tiny qtsingleapp-Viber-0-3e8 qtsingleapp-Viber-0-3e8-lockfile ssh-QEhD246wugPL unity_support_test.0 DEVICE 1 Command executed: vmstat procs -----------memory---------- ---swap-- -----io---- -system-- ---- +--cpu----- r b swpd free buff cache si so bi bo in cs us s +y id wa st 5 0 152888 584588 22596 1091568 1 8 83 125 771 491 40 + 6 53 1 0 DEVICE 2 Command executed: ls /tmp foo.txt orbit-tiny qtsingleapp-Viber-0-3e8 qtsingleapp-Viber-0-3e8-lockfile ssh-QEhD246wugPL unity_support_test.0 DEVICE 2 Command executed: vmstat procs -----------memory---------- ---swap-- -----io---- -system-- ---- +--cpu----- r b swpd free buff cache si so bi bo in cs us s +y id wa st 1 0 152888 584596 22596 1091568 1 8 83 125 771 492 40 + 6 53 1 0 DEVICE 1 Command executed: ls /tmp foo.txt orbit-tiny qtsingleapp-Viber-0-3e8 qtsingleapp-Viber-0-3e8-lockfile ssh-QEhD246wugPL unity_support_test.0 DEVICE 1 Command executed: vmstat procs -----------memory---------- ---swap-- -----io---- -system-- ---- +--cpu----- r b swpd free buff cache si so bi bo in cs us s +y id wa st 5 0 152888 584588 22596 1091568 1 8 83 125 771 491 40 + 6 53 1 0 DEVICE 2 Command executed: ls /tmp foo.txt orbit-tiny qtsingleapp-Viber-0-3e8 qtsingleapp-Viber-0-3e8-lockfile ssh-QEhD246wugPL unity_support_test.0 DEVICE 2 Command executed: vmstat procs -----------memory---------- ---swap-- -----io---- -system-- ---- +--cpu----- r b swpd free buff cache si so bi bo in cs us s +y id wa st 1 0 152888 584596 22596 1091568 1 8 83 125 771 492 40 + 6 53 1 0 DEVICE 3 Command executed: ls /tmp foo.txt orbit-tiny qtsingleapp-Viber-0-3e8 qtsingleapp-Viber-0-3e8-lockfile ssh-QEhD246wugPL unity_support_test.0 DEVICE 3 Command executed: vmstat procs -----------memory---------- ---swap-- -----io---- -system-- ---- +--cpu----- r b swpd free buff cache si so bi bo in cs us s +y id wa st 1 0 152888 584720 22596 1091568 1 8 83 125 771 492 40 + 6 53 1 0 $VAR1 = { 'DEVICE 2' => [ 'ls /tmp', 'vmstat' ], 'DEVICE 1' => [ 'ls /tmp', 'vmstat' ], 'DEVICE 3' => [ 'ls /tmp', 'vmstat' ] };

    The conf.ini file is attached in the previous answer.

    Hope this is what you where looking for, let me know how it worked for you.

    Seeking for Perl wisdom...on the process of learning...not there...yet!

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1101698]
Approved by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others contemplating the Monastery: (4)
As of 2024-04-24 01:20 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found