I'm new to perl and facing a problem........ I'm using a perl
expect script to login to multiple machines (having same username and
password) and execute the date command, initially i tested on one machine,
it worked fine...........but when i use a foreach loop to test the same
thing on two machines (the code is shown below), it didn't work.......it
just worked on the first machine (10.10.10.1) ........can someone please
help me out with this problem?......how can i use the perl expect script to
login to the multiple machines (assuming they have same username and
password) and execute commands?.. Kindly help me with this problem
#############################################################
#!/usr/bin/perl -w
use strict;
use Expect;
foreach ("10.10.10.1", "10.10.10.2") {
print "Spawning to the $_\n";
$exp->spawn("ssh -l username $_") or warn "unable to spawn: $!";
#This part checks for the password prompt, if it doesn't get the password
prompt the errors are displayed.
unless($exp->expect(10, '-re','.*password:\s*')){
if( $exp->before()) {
print $exp->before();
print "\n";
}
else {
print "Timed out\n";
}
next;
}
print "Sending password to the host\n";
$exp->send("password\r");
print "\n";
#This code will handle any errors after the password is sent
unless($exp->expect(10, '-re', '.*[#$>]')) {
if($exp->before() =~ /(Permission.*\s*.*)/) {
print "\n";
print "Invalid password\n";
}
else {
print "timed out\n";
}
exit;
}
print "sending date command\n";
$exp->send("date\r");
$exp->expect(15, '-re', '.*[#$>]' );
$exp->soft_close();
}
#############################################################
I know this is a Perl question but is not more easier to log in with
ssh public key method and execute the commands inside the foreach and
don't do all the username/password code?
Regards,
Alvaro
Sorry...probably my bad English wasn't clear enough:
1.- You need one valid ssh account on each server (even if it is a
cluster of servers).
2.- SSH let's you execute remote commands on that servers.
3.- The perl script executes commands on that servers
4.- Expect do his part of the job with the outputs of the commands
executed.
So, you can share your public ssh key in each target server to log in
directly with the valid ssh account without a password (and save
yourself about the first part of the perl/expect code about the
authentication part using a much easier method to log in) and get a
valid procedure to execute the commands.
I agree with you that it is much easier to define the list of servers
with a var or maybe open a file...or whaterever...with that information.
Then the "foreach" just need to read that and execute the commands but
free of the too much code doing the authentication and validation
responses about the username/password.
Don't you think?
Regards,
Alvaro
> >>
> >> foreach ("10.10.10.1", "10.10.10.2") {
> >> print "Spawning to the $_\n";
> >> $exp->spawn("ssh -l username $_") or warn "unable to spawn: $!";
>
> Don't you think it is much clearer to add a name to the default var? Like this:
>
> my @servers = qw/ 10.10.10.1 10.10.10.2 /;
> foreach my $server (@servers)
> print "Spawning to $server\n";
> $exp->spawn("ssh -l username $_") or warn "unable to spawn: $!";
>
> >>
> >>
> >> #This part checks for the password prompt, if it doesn't get the password
> >> prompt the errors are displayed.
> >> unless($exp->expect(10, '-re','.*password:\s*')){
>
> I haven't tested all your code, but expect is notoriously difficult to use. Matching the prompt and such exactly is a pain. Expect itself offers a little bit easier debugging output sometimes too.
>
> Jeremiah
No idea really but you might want to invoke ssh with debug settings
for possible additional clues:
spawn("ssh -v -l username .... ") ... # man ssh
--
Charles DeRykus
There are several CPAN modules (Net::OpenSSH, Net::SSH2, Net::SSH::Perl,
Net::SSH::Expect) that allow to run commands in remote machines through
SSH. Any one of them will release you of the burden of handling
authentication and capturing the output of the remote command.
For instance:
use Net::OpenSSH;
for my $host (@hosts) {
my $ssh = Net::OpenSSH->new($host, user => $user, passwd => $passwd);
if ($ssh->error) {
warn "unable to connect to $host: ". $ssh->error;
next;
}
my $date = $ssh->capture('date');
print "$host: $date";
}
- Salva
> Hello,
>
> I know this is a Perl question but is not more easier to log in with
> ssh public key method and execute the commands inside the foreach and
> don't do all the username/password code?
Sometimes - like when you have a cluster of machines - it is easier and faster to write a command once and have it execute on all the machines. Expect is really good for this since you can just feed it a list of machines and commands and expect just goes and does its thing.
>>
>> foreach ("10.10.10.1", "10.10.10.2") {
>> print "Spawning to the $_\n";
>> $exp->spawn("ssh -l username $_") or warn "unable to spawn: $!";
Don't you think it is much clearer to add a name to the default var? Like this:
my @servers = qw/ 10.10.10.1 10.10.10.2 /;
foreach my $server (@servers)
print "Spawning to $server\n";
$exp->spawn("ssh -l username $_") or warn "unable to spawn: $!";
>>
>>
>> #This part checks for the password prompt, if it doesn't get the password
>> prompt the errors are displayed.
>> unless($exp->expect(10, '-re','.*password:\s*')){
I haven't tested all your code, but expect is notoriously difficult to use. Matching the prompt and such exactly is a pain. Expect itself offers a little bit easier debugging output sometimes too.
Jeremiah
I got the solution for this problem..........the reason is that
the new expect object had to be created for each machine that is
$exp = new Expect has to be inside the foreach loop, in my earlier code it
was outside the foreach loop.....Thanks you all for the solutions......i
tried using Net::SSH2 and Net::SSH::Perl and it didn't work for me so i had
to use expect.
Thanks