Unknown reason for Known error in the perl script - perl

I am writing following script to read list of servers from the text file them ssh to them and run ldd command to fetch the version that is installed on the server.
The only problem is the error that I am seeing following error which says Bad Host name:
adev#abclnxdev:[/home/adev/perl-scripts] {63} % perl try.pl
Net::SSH: Bad host name: abclnxtest01
at try.pl line 21
when I manually do the ssh to this host. It gets connect.
Here is script :
#!/mu/bin/perl
use Net::SSH::Perl;
use warnings;
my $file = "server-list.txt";
my $usr = "user";
my $pwd = "password";
my $output_file = "GlibC-version.txt";
open(HANDLE, $file) or die("Cant open the file :( ");
#server_list = <HANDLE>;
close(HANDLE);
#debug_print_array(#server_list);
open(HANDLE, ">>$output_file"); #opening file for output.
foreach $host (#server_list)
{
my $ssh = Net::SSH::Perl->new($host);
$ssh->login($usr,$pwd,$ssh);
my($stdout, $stderr, $exit) = $ssh->cmd("ldd --version|grep ldd");
print HANDLE "----------------------------------";
print HANDLE "Hostname : $host";
print HANDLE "GLIBC Version : $stdout";
print HANDLE "----------------------------------\n\n";
}

You have a newline at the end of the server name.
Add:
chomp #server_list;
(And incidentally, it's better to use the newer 3-argument open(); see http://perlmaven.com/open-files-in-the-old-way .)

Related

Parallel::ForkManager gives - child process STDIN is not a real system Error

I have a script which does ssh to number if servers(#hosts) stored in an array and executes certain commands on those hosts.
...
use Net::OpenSSH;
use Parallel::ForkManager;
#these hosts are the IP addresses
my #hosts = ("host1", "host2", "host3", "host4", "host5");
my $ssh;
my $command = "perl -e "print \"Hello..\"";
my $pm = Parallel::ForkManager->new(5);
LOOP:
foreach my $n (#hosts) {
my $pid = $pm->start and next LOOP;
#doing ssh to the host and running the command
#lets say here I am executing simple Perl command
$ssh = Connect($n, "user", "passwd");
$ssh->capture($command);
$pm->finish;
}
$pm->wait_all_children;
undef $ssh;
sub Connect {
my ( $host, $user, $passwd ) = #_;
my $ssh = Net::OpenSSH->new($host, user=>$user, password=>$passwd);
$ssh->error and die "Couldn't establish SSH connection: " . $ssh->error;
return $ssh;
}
...
When I execute this script, I am getting below error which is like nightmare to me.
child process STDIN is not a real system file handle at (eval 2) line 145
I don't why this error occurs. Could someone please help me to resolve this issue.
Am I missing something in $pm->finish or do I need to add $pm->run_on_finish(..) ?

How to switch different strings from file in a while loop using Perl

I have a question, it is probably an easy one, but I haven't found the answer for it.
I have a file of strings (each string in a separate line, and I need to use each string (line) in the cmd.
I'm using a 'while' loop, but I don't know how to append each string to the loop.
I need to run the following when the XXX.XXX.XXX is the string that needs to be changed in the loop.
c:\putty\putty.exe -ssh "root#XXX.XXX.XXX.XXX" -pw "password" -m "c:\putty\putty.txt"
Try this:
#!/usr/bin/perl
use warnings;
use strict;
open my $fh, "<", "file.txt" or die $!;
while (my $line = <$fh>)
{
chomp $line;
#Here you can replace 'XXX.XXX.XXX' with '$line'. Modify below line as per your requirement.
my $cmd = `c:\\putty\\putty.exe -ssh "root\#$line" -pw "password" -m "c:\\putty\\putty.txt"`;
}
close $fh;
More detailed version would be:
use strict;
use warnings;
my $file = "file_of_strings.file";
# Open file and read contents before closing handle
open(FH, "<", $file) or die "Unable to open \"$file\" $!";
chomp(my #users = <FH>);
close(FH);
for my $user (#users) {
# Frame remote command
my $cmd = "c:\putty\putty.exe -ssh 'root\#${user}' -pw 'password' -m 'c:\putty\putty.txt'";
if (system $cmd != 0) { # system command returns 0 on successful execution
print "Successfully executed command: $cmd\n";
} else {
print "Failed to execute command: $cmd exited $? $!\n"; # Better to log the exit code ($?) and error message, if any($!).
}
}

Create a file in remote linux machine

I want to create a file in remote Linux machine from my local windows machine.
The file which will be created should be of 10 lines
like
E-762334|UC5L0001|2.6.7.1.0.12.0.0.0.372|3.0.0|20130917193000|12
E-762334|UC5L0001|2.6.7.1.0.12.0.0.0.372|3.0.0|20130917194000|13
E-762334|UC5L0001|2.6.7.1.0.12.0.0.0.372|3.0.0|20130917195000|14
E-762334|UC5L0001|2.6.7.1.0.12.0.0.0.372|3.0.0|20130917196001|15
E-762334|UC5L0001|2.6.7.1.0.12.0.0.0.372|3.0.0|20130917193002|6
E-762334|UC5L0001|2.6.7.1.0.12.0.0.0.372|3.0.0|20130917193500|13
E-762334|UC5L0001|2.6.7.1.0.12.0.0.0.372|3.0.0|20130917193700|1
E-762334|UC5L0001|2.6.7.1.0.12.0.0.0.372|3.0.0|20130917193200|13
My code:
use Net::SSH2::Simple;
use Net::SSH2;
my $ssh2 = Net::SSH2::Simple->new();
$ssh2->connect('host') or die "Unable to connect Host $# \n";
$ssh2->auth_password('user','password') or die "Unable to login $# \n";
my $test = <<'END';
E-762334|UC5L0001|2.6.7.1.0.12.0.0.0.372|3.0.0|20130917193000|12
E-762334|UC5L0001|2.6.7.1.0.12.0.0.0.372|3.0.0|20130917194000|13
E-762334|UC5L0001|2.6.7.1.0.12.0.0.0.372|3.0.0|20130917195000|14
END
my $cmd="echo $test > /data/spanda/pppp1";
($stdout,$stderr, $exitcode) = $ssh2->cmd($cmd ,'bufsize' => 4_096 ) or die "cannot execute command: ";
if ($exitcode == 0) {
print $stdout if $stdout;
print $stderr if $stderr;
} else {
print $stderr if $stderr;
die "command failed with exit code $exitcode";
}
I am getting Error like
13: Command not found.
E-762334: Command not found.
UC5L0001: Command not found.
2.6.7.1.0.12.0.0.0.372: Command not found.
3.0.0: Command not found.
Your command doesn't work for the same reason as echo foo|bar > /tmp/x doesn't work (strings with pipes should be quoted).
On the other hand there is more robust method; Net::SSH2::Simple inherits from Net::SSH2 which in turn can return Net::SSH2::SFTP object,
use Fcntl;
# my $sftp = $ssh2->sftp();
my $fh = $ssh2->sftp->open('/data/spanda/pppp1', O_WRONLY|O_CREAT) or die;
print $fh $test;

Diff two remote files using Perl

I have an array of file paths:
#files = ('/home/.../file.txt', '/home/.../file2.txt',...);
I have multiple remote machines, with a similar filestructure. How can I diff these remote files using Perl?
I thought of using Perl backticks, ssh and using diff, but I am having issues with sh (it doesn't like diff <() <()).
Is there a good Perl way of comparing at least two remote files?
Use rsync to copy the remote files to the local machine, then use diff to find out the differences:
use Net::OpenSSH;
my $ssh1 = Net::OpenSSH->new($host1);
$ssh1->rsync_get($file, 'master');
my $ssh2 = Net::OpenSSH->new($host2);
system('cp -R master remote');
$ssh2->rsync_get($file, 'remote');
system('diff -u master remote');
You can use the Perl Module on CPAN called Net::SSH::Perl to run remote commands.
Link: http://metacpan.org/pod/Net::SSH::Perl
Example from the Synopsis:
use Net::SSH::Perl;
my $ssh = Net::SSH::Perl->new($host);
$ssh->login($user, $pass);
my($stdout, $stderr, $exit) = $ssh->cmd($cmd);
You command would look something like
my $cmd = "diff /home/.../file.txt /home/.../file2.txt";
edit: The files are on different servers.
You can still use Net::SSH::Perl to read the files.
#!/bin/perl
use strict;
use warnings;
use Net::SSH::Perl;
my $host = "First_host_name";
my $user = "First_user_name";
my $pass = "First_password";
my $cmd1 = "cat /home/.../file1";
my $ssh = Net::SSH::Perl->new($host);
$ssh->login($user, $pass);
my($stdout1, $stderr1, $exit1) = $ssh->cmd($cmd1);
#now stdout1 has the contents of the first file
$host = "Second_host_name";
$user = "Second_user_name";
$pass = "Second_password";
my $cmd2 = "cat /home/.../file2";
$ssh = Net::SSH::Perl->new($host);
$ssh->login($user, $pass);
my($stdout2, $stderr2, $exit2) = $ssh->cmd($cmd2);
#now stdout2 has the contents of the second file
#write the contents to local files to diff
open(my $fh1, '>', "./temp_file1") or DIE "Failed to open file 1";
print $fh1 $stdout1;
close $fh1;
open(my $fh2, '>', "./temp_file2") or DIE "Failed to open file 2";
print $fh2 $stdout2;
close $fh2;
my $difference = `diff ./temp_file1 ./temp_file2`;
print $difference . "\n";
I haven't tested this code, but you could do something like this. Remember to download the Perl Module Net::SSH::Perl to run remote commands.
Diff is not implemented in the Perl Core Modules, but there another called Text::Diff on CPAN so maybe that would work too. Hope this helps!

ssh login verification in perl

I am running following lines of code in perl script to find a df output of remote machines. this works fine and gather a info in #df_ret untill until ssh key is uptodate. if public is corrupted or changed, its not showing any sign of error in script. if i run manually then i will be asked for the password.
#df_ret = split /\n/, `ssh -q $server 'df -hP'`;
Is there any way i can verify that if ssh login is successful then this perl script line should be executed else not. been finding many searches on it but could not reach to the ONE. any help?
I have got one solution working as below;
#!/usr/local/bin/perl
my $line = `ssh $server -o 'BatchMode=yes' -o 'ConnectionAttempts=1' true`;
my $error = `echo $?`;
print "Error = $error";
if($error == 0 )
{
print "This is good";
#df_ret = split /\n/, `ssh -q $server 'df -hP'`;
}
else
{
print "This is bad";
}
Check the result of the ssh exec before splitting it:
$text = `ssh -q $server 'df -hP'` or die "unable to ssh\n";
#df_ret = split /\n/, $text;