Output Lines are missing - perl

I have written small program for getting output from router. but the starting content of the output is missing in output file.
#!C:\strawberry\perl\bin\perl -w
open ( OUTPUT,"> D:\\Routerbkp\\router\\abc.txt" );
use Control::CLI;
# Create the object instance for SSH
$cli = new Control::CLI('SSH');
# Connect to host - Note that with SSH,
# authentication is part of the connection process
$cli->connect( Host => '10.0.0.1',
Username => 'abc',
Password => 'abc',
PrivateKey => 'C:\Users\Administrator\.ssh\key_10.0.0.1_22.pub',
);
# Send a command and read the resulting output
$output1 = $cli->cmd("terminal length 0");
sleep(1);
$output2 = $cli->cmd("show running-config");
sleep(5);
$output8 = $cli->cmd("show alarm current");
sleep(2);
$cli->disconnect;
print OUTPUT $output1;
print OUTPUT $output2;
print OUTPUT $output8;

If you're having a problem with your code, your first port of call is ALWAYS use strict; and use warnings;.
Then - fix that open statement. Try in the style of:
open ( my $output_fh, ">", "D:\\Routerbkp\\router\\abc.txt" ) or die $!;
You probably also want to trap any errors from $cli -> connect() because there's no guarantee that's worked.
my $result = $cli -> connect ( ...
if ( not $result ) { print "Connect failed: ", $cli -> errormode(), ":", $cli -> errormsg(), "\n"; };

Related

use of uninitialized value. How can I fix this error?

#!/usr/bin/perl
use Net::SSH::Expect;
use warnings;
use strict;
#my($stdout, $stderr, $exit) = $ssh->cmd("ls -l /home/$usr")
# Making an ssh connection with user-password authentication
# 1) construct the object
my $ssh = Net::SSH::Expect->new (
host => "host",
password=> 'pwd',
user => 'user',
raw_pty => 1
#Expect=>log_file("finally.txt")
);
# 2) logon to the SSH server using those credentials.
# test the login output to make sure we had success
my $login_output = $ssh->login();
if ($login_output !~ /Welcome/) {
die "Login has failed. Login output was $login_output";
}
# disable terminal translations and echo on the SSH server
# executing on the server the stty command:
$ssh->exec("stty raw -echo");
my $stdout = $ssh->send(chr(13));
my $stdout2 = $ssh->send("SDT-FI");
my $stdout3 = $ssh->send("ENG");
my $stdout4 = $ssh->send('SORT FI-WIP "84144"');
my $stdout5 = $ssh->send(chr(13));
my $stdout6 = $ssh->send("OFF");
my $stdout7 = $ssh->send(chr(13));
print($stdout3);
#$expect->log_file("adp-n.txt");
#y $line;
# returns the next line, removing it from the input stream:
# while ( defined ($line = $ssh->read_all()) ) {
# print $line . "\n";
#}
So i am trying to print $stdout3 so i can get information about the output
but i keep getting " use of uninitialized value $stdout3 in print at connnn3.pl line 50"
is there something in my code wrong?
how can i fix this?
UPDATE, SOLVED!
The reason why it was returning "use of uninitialized value" was because the function
send()
Is void, so instead i used
exec()
And that solved it
From the documentation of Net::SSH::Expect:
void send($string) - sends $string to the SSH server, returns nothing
Thus, send obviously returns nothing (void) and that's why you get this warning when trying to print the (non-existing) return value of send. If you want to get data back from the server use peek, eat, read_all or similar as documented.

Perl: Separate log for each device & convert IP to hostname from the log filenames

I have created a perl that telnet to multiple switches. My code is generates only one log file output for multiple Cisco switches.
What should I do to create separate log file for each device status(include telnet failure)?
And how could I convert IP to hostname from the log filenames?
Desired output log files one by one, hostname1.log, hostname2.log, hostname3.log......so on and so forth.
Here is my code:
#!/usr/bin/perl
use strict;
use warnings;
use Net::Cisco;
my $username="danny";
my $pass="1234";
open (OUTPUT, ">intstatus.log" );
open (IP, "ip.txt") or die $!;
for my $line (<IP>) {
chomp $line;
$line =~ s/\t+//;
print $line, "\n";
SWTELNET($line); # pass $line as the argument to SWTELNET
}
sub SWTELNET {
my $host = shift; # $host is set to the first argument passed in from the above loop
my $t = Net::Telnet::Cisco -> new (
Host => $host,
Prompt => '/(?m:^(?:[\w.\/]+\:)?[\w.-]+\s?(?:\(config[^\)]*\))?\s?[\$#>]\s?(?:\(enable\))?\s*$)/',
Timeout => 6,
Errmode => 'return',
) or die "connect failed: $!";
if ($t->login($username,$pass)) {
$t->autopage;
$t->always_waitfor_prompt;
my #supenv=$t->cmd("show ip int br");
my #output = ();
print OUTPUT "$host\n#supenv\n";
}
}
close(IP);
close(OUTPUT);
I don't have any telnet devices to test with, but this should at least get you most of the way. It uses gethostbyaddr() from Socket to try to resolve the IP back to a hostname (and falls back to using the IP as hostname if the name can't be found). It also uses the proper three-argument form of open with lexical file handles (as opposed to bareword handles), and it opens a new log file for writing in the format hostname.log for each host found in the input file.
use warnings;
use strict;
use Net::Telnet::Cisco;
use Socket;
my $username="danny";
my $pass="1234";
open my $infile, '<', "ip.txt" or die $!;
for my $ip (<$infile>) {
chomp $ip;
$ip =~ s/\t+//;
# resolve IP to hostname if possible
my $host = gethostbyaddr(inet_aton($ip), AF_INET);
$host = $ip if ! $host;
SWTELNET($host);
}
close $infile;
sub SWTELNET {
my $host = shift;
my $t = Net::Telnet::Cisco->new(
Host => $host,
Prompt => '/(?m:^(?:[\w.\/]+\:)?[\w.-]+\s?(?:\(config[^\)]*\))?\s?[\$#>]\s?(?:\(enable\))?\s*$)/',
Timeout => 6,
Errmode => 'return',
) or die "connect failed: $!";
if ($t->login($username,$pass)) {
$t->autopage;
$t->always_waitfor_prompt;
my #supenv=$t->cmd("show ip int br");
# no need to manually close the file after, as it'll happen
# automatically as soon as the scope ends
open my $wfh, '>', "$host.log";
print $wfh "$host\n#supenv\n";
}
}

Perl - Output the log files

I have created a perl that telnet to multiple switches. I would like to check if telnet functions properly by telneting the switch.
This is my code to telnet to the switches:
#!/usr/bin/perl
use warnings;
use Net::Cisco;
open( OUTPUT, ">log.txt" );
open( SWITCHIP, "ip.txt" ) or die "couldn't open ip.txt";
my $count = 0;
while (<SWITCHIP>) {
chomp($_);
my $switch = $_;
my $tl = 0;
my $t = Net::Telnet::Cisco->new(
Host => $switch,
Prompt =>
'/(?m:^(?:[\w.\/]+\:)?[\w.-]+\s?(?:\(config[^\)]*\))?\s?[\$#>]\s?(?:\(enable\))?\s*$)/',
Timeout => 5,
Errmode => 'return'
) or $tl = 1;
my #output = ();
if ( $tl != 1 ) {
print "$switch Telnet success\n";
}
else {
my $telnetstat = "Telnet Failed";
print "$switch $telnetstat\n";
}
close(OUTPUT);
$count++;
}
This is my output status after I was testing 7 switches:
10.xxx.3.17 Telnet success
10.xxx.10.12 Telnet success
10.xxx.136.10 Telnet success
10.xxx.136.12 Telnet success
10.xxx.188.188 Telnet Failed
10.xxx.136.13 Telnet success
I would like to convert the telnet result as log file.
How to separate successful and failed telnet results by using perl?
Please Try the following
#!/usr/bin/perl
use warnings;
use Net::Cisco;
################################### S
open( OUTPUTS, ">log_Success.txt" );
open( OUTPUTF, ">log_Fail.txt" );
################################### E
open( SWITCHIP, "ip.txt" ) or die "couldn't open ip.txt";
my $count = 0;
while (<SWITCHIP>) {
chomp($_);
my $switch = $_;
my $tl = 0;
my $t = Net::Telnet::Cisco->new(
Host => $switch,
Prompt =>
'/(?m:^(?:[\w.\/]+\:)?[\w.-]+\s?(?:\(config[^\)]*\))?\s?[\$#>]\s?(?:\(enable\))?\s*$)/',
Timeout => 5,
Errmode => 'return'
) or $tl = 1;
my #output = ();
################################### S
if ( $tl != 1 ) {
print "$switch Telnet success\n"; # for printing it in screen
print OUTPUTS "$switch Telnet success\n"; # it will print it in the log_Success.txt
}
else {
my $telnetstat = "Telnet Failed";
print "$switch $telnetstat\n"; # for printing it in screen
print OUTPUTF "$switch $telnetstat\n"; # it will print it in the log_Fail.txt
}
################################### E
$count++;
}
################################### S
close(SWITCHIP);
close(OUTPUTS);
close(OUTPUTF);
################################### E
In print statement after print just write the filehandle name which is OUTPUT in your code:
print OUTPUT "$switch Telnet success\n";
and
print OUTPUT "$switch $telnetstat\n";
A side note: always use a lexical filehandle and three arguments with error handling to open a file. This line open(OUTPUT, ">log.txt"); you can write like this:
open my $fhout, ">", "log.txt" or die $!;
Use Sys::Syslog to write log messages.
But since you're opening a log.txt file with the handle OUTPUT, just change your two print statements to have OUTPUT as the first argument and the string as the next (without a comma).
my $telnetstat;
if($tl != 1) {
$telnetstat = "Telnet success";
} else {
$telnetstat = "Telnet Failed";
}
print OUTPUT "$switch $telnetstat\n";
# Or the shorter ternary operator line for all the above:
print OUTPUT $swtich . (!$tl ? " Telnet success\n" : " Telnet failed\n");
You might consider moving close to an END block:
END {
close(OUTPUT);
}
Not only because it's in your while loop.

passing variable to mongodb query in perl

I want to query a list of nickname from a text file.
#!/usr/bin/perl
use strict;
use warnings;
use MongoDB;
# Open file
print "--> Read file\n";
open( INPUT, "<userlist.txt" ) or die "Could not open the file: $!\n";
print "--> Read INPUT OK\n";
open( OUTPUT, ">>outfile.txt" ) or die "Could not open the file: $!\n";
print "--> Read OUTPUT OK\n";
# MongoDB parameter
my $mongoHost = localhost;
my $mongoPort = 12345;
my $conn = MongoDB::Connection->new( "host" => "$mongoHost", "port" => $mongoPort ); # Open connection
my $db = $conn->mylist; # Connect to database
my $user_stats = $db->user_stats; # Choose a collection
print "--> Connect to MongoDB\n";
# Read through line
foreach my $line ( <INPUT> ) {
# Extract content
chomp( $line ); # Remove newline
print "$line\n";
my $statsResult = $user_stats->find( { nickname => '$line' } );
while ( my $obj = $statsResult->next ) {
print $obj->{ "nickname" } . ";";
print $obj->{ "total" } . "\n";
}
}
close( OUTPUT );
close( INPUT );
print "--> End of Code\n";
exit 0;
It seem it fail to recognise variable $line at the line my $statsResult = $user_stats->find( { msisdn => '$line' } );
It works if I replace $line with a string like mynickname. The print statement in previously works ok.
Am I missing something here?
You're using single quotes in your line
my $statsResult = $user_stats->find( { nickname => '$line' } );
Meaning that the database is being searched for the string $line, not the contents of the variable. Remove the single quotes and you should be fine.
Also, here's a nice tutorial on the different forms of quoting in Perl, which explains why single quotes are different from double quotes, what qq means, etc.

Perl: SSH Tail as File Handler

I am creating a log parser that has the ability to "stream" a log as it is written.
The log resides on a remote host, so I am creating a file handler using a combination of
SSH and tail. The following works quite well, but I do have some questions regarding error handling.
If the user doesn't enter the password for the SSH connection prior to the alarm delay expiring, the alarm will start triggering. This leads to the console being cleared so it is not clear that the password needs to be entered.
If i enter the wrong password, i still enable the alarm leading to screen clears, ect...
Password:
Password:
Password:
Permission denied (publickey,keyboard-interactive).
If i provide a log filename that doesn't exist, the code continues....
tail: cannot open `/path_to_log/mylog.logXXXX' for reading: No such file or directory
tail: no files remaining
So, my question is what is the best way add some additional error handling. Alternatively, can the File::Tail module be used in combination with SSH, telnet, rlogin, etc to provide the same functionality?
Thanks!
my $stopMsg = "Use CTRL+C to stop streaming at any time...\n";
my $SSH = sprintf "ssh %s#%s tail -f %s | ", $user, $host, $log;
printf "Log: %s\n", $log;
printf "Handle: %s\n", $SSH;
my $errMsg = sprintf "Couldn't establish SSH connection to \"%s\":",
$host;
open my $pipe, $SSH or error( $errMsg );
my $loadTime = time;
printf $stopMsg;
setSignalHandler( 'INT', sub{ stopAlarm( TRUE ); } );
startAlarm( $delay,
$interval,
sub { system "clear"; $handler->( \#sysLogArr ); printf $stopMsg; } );
while ( alarmHandlerSet() )
{
my $data = <$pipe>;
next unless defined $data;
mapSysLog( line => $data,
arrRef => $logRef,
varRef => \%sysLogVars,
dbRef => $dbRef );
}
clearSignalHandler( 'INT' );
sub error(#)
{
my $color = "BOLD";
$color = $CONFIG{errorPrinter} if ( $CONFIG{colorEnable} &&
defined $CONFIG{errorPrinter} );
color2PrinterRef( $color )->( "\nERROR: " );
printf "%s\n", shift;
printf " %s\n", $_ foreach ( #_ );
printf "Called From: %s::%d\n", (caller)[1], (caller)[2];
printf "\n";
exit EXIT_FAILURE;
}
See the sftp_tail.pl sample included with Net::SFTP::Foreign.