net-sftp-foreign error handling for nagios integration - perl

I am rather new in Perl. I have written a very simple script that copies and removes a file from sftp.
but the script should return some kind of output in order to integrate it with nagios.. using nsca or something.
the script is running on solaris 10.
here is the script:
#!/usr/bin/perl -w
use strict;
use warnings;
use Net::SFTP::Foreign;
use POSIX qw(strftime);
my $datestring =strftime "%d-%m-%Y", localtime;
my $host="sftp.mariog.com";
my $username="user";
my $local="/mnt/mariog";
my $file="BookingReport_Daily_$datestring.xls";
print "$file \n";
my $sftp = Net::SFTP::Foreign->new($host,
user => $username,
stderr_discard => 1,
autodie => 1,
);
$sftp->die_on_error("unable to establish SFTP Connection");
$sftp->get("$file", "$local/$file");
$sftp->remove($file);
$sftp->disconnect();
how to handle the fact that the file does not exist on the sftp? maybe it has not reached yet. there a daily file uploaded but at different times. the script is run by cron every 4 hours so most of the times it will not find files to transfer...
where can I get the output code of the transfer successful or not? so that i can pass it to a nagios passive check with nsca...
thank you for your help..
kind regards.
Mario

It looks like one way to check for a successful get in the documentation would be something like this:
$sftp->get("$file", "$local/$file") or die "get failed:" $sftp->error;

Related

psftp error flag using in perl

The script below functions just as intended. It calls the batch file which establishes a connection using PUTTY or scpecically psftp and transfers a handful of file. Once the transfer is complete i continue with the perl script to move the files to another directory.
My question is how could I capture an error from the PSFTP application? If there is an error xfering or establishing a connection i would like to generate a flag which then i could capture in perl and stop anything else from happening and send me an email. I just need guidance on generating the flag from the PSFTP application on error.
Thank you very much in advance!
My
use warnings;
use File::Copy;
my $TheInputDir = "//NT6/InfoSys/PatientSurvey/Invision/CFVMC/";
my $TheMoveDir = "//NT6/InfoSys/PatientSurvey/Invision/CFVMC/Completed";
system ('2166_PG_Upload_Batch.bat');
opendir (THEINPUTDIR, $TheInputDir);
#TheFiles = readdir(THEINPUTDIR);
close THEINPUTDIR;
#Get all the files that meet the naming convention
foreach $TheFile(#TheFiles)
{
if($TheFile =~ /2166/)
{
print "$TheFile\n";
move ("$TheInputDir$TheFile","$TheMoveDir");
}
}
You should read STDERR from your application into Perl. For that use Capture::Tiny
my ($stdout, $stderr, $exit) = capture {
system('2166_PG_Upload_Batch.bat');
};
#check for $stderr and do your stuffs i.e sending email etc
For more info refer perlfaq

Weird issue with Net::SSH::Expect in Perl script

I am working on putting together a perl script. I have captured it below:
#!/usr/bin/perl
use Tie::File;
use Net::SSH::Expect;
use utf8;
use warnings;
use diagnostics;
# Grab password from hidden file
$pw=`cat .password`;
chomp $pw;
#Read list of 9200's from hosts.list file into an array
tie #hosts, 'Tie::File', "hosts.list" or die;
#Loop through hosts, connect via ssh, run commands, and write out log files.
foreach (#hosts) {
#Create ssh session handle
my $ssh = Net::SSH::Expect->new (
host => $_,
password => $pw,
user => 'user',
raw_pty => 1
);
my $login_output = $ssh->login();
if ($login_output !~ /.*sbc.*>/) {
die "Login failed. Login output was $login_output";
}
$ssh->send("show sip errors");
my $line;
while ( defined ($line = $ssh->read_line()) ){
print $line . "\n";
}
$ssh->close();
}
First, I'm not a programmer, so style is probably very ugly. Sorry about that :) The goal is to run several commands on a remote appliance, capture the results in separate files, which will then be consumed by a 3rd party parsing engine (splunk).
The current implemented functionality is able to log in to remote hosts, run the command, and then print out to stdout. Not quite there, but still shows a good proof of concept.
The script runs fine for the first 3 hosts in the hosts.list file. However as soon as it gets to the fourth host, I receive this exception:
Uncaught exception from user code:
SSHAuthenticationError Login timed out. The input stream currently has the contents bellow: user#myhost.mydomain's password: at /System/Library/Perl/Extras/5.12/Expect.pm line 828
at /Library/Perl/5.12/Net/SSH/Expect.pm line 209
Net::SSH::Expect::__ANON__('ARRAY(0x7fd718a03008)') called at /System/Library/Perl/Extras/5.12/Expect.pm line 828
Expect::_multi_expect(1, 'ARRAY(0x7fd7189fbce8)', 'ARRAY(0x7fd7189f7460)') called at /System/Library/Perl/Extras/5.12/Expect.pm line 565
Expect::expect('Expect=GLOB(0x7fd7189f1878)', 1, 'ARRAY(0x7fd718a01530)', 'ARRAY(0x7fd7189f15a8)', 'ARRAY(0x7fd71890a3d0)', 'ARRAY(0x7fd718a07470)', 'ARRAY(0x7fd7189d8b18)') called at /Library/Perl/5.12/Net/SSH/Expect.pm line 580
Net::SSH::Expect::_sec_expect('Net::SSH::Expect=HASH(0x7fd718a29828)', 1, 'ARRAY(0x7fd718a01530)', 'ARRAY(0x7fd7189f15a8)', 'ARRAY(0x7fd71890a3d0)', 'ARRAY(0x7fd718a07470)', 'ARRAY(0x7fd7189d8b18)') called at /Library/Perl/5.12/Net/SSH/Expect.pm line 213
Net::SSH::Expect::login('Net::SSH::Expect=HASH(0x7fd718a29828)') called at ./pcscfFetch.pl line 26
Any ideas on what the problem could be? I am able to log in to the host with no issue manually via ssh. The script works fine for our other hosts, it's just this one outlier that I can't seem to figure out. Any advice would be appreciated. Thanks!
I did end up resolving this. In the constructor for $ssh I set the timeout to 10 seconds, instead of the default 1. The script runs significantly slower, but I don't appear to have the issues I was running into before. Appreciate the feedback!
Net::SSH::Expect is not reliable.
Use Net::OpenSSH instead, or if you want to run the same set of commands in several hosts Net::OpenSSH::Parallel.

Creating a script to delete old log files, that allows me to pass directory/age/regex arguments

I'm trying to create a PERL script to delete old log files. One of the key things I want the script to be able to do is allow me to pass arguments for directory, name of the file (such as test.log-*), and age of the file.
It's been a while since I've used PERL and I'm not that great anyway, so I'd appreciate some help. I'm also not terribly familiar with the getopt::long module. Here's what I'm thinking so far, and while I'm sure it's not correct, please give me any feedback that might assist.
I want to run the script along the lines of "script.pl --dir /release/logs --type test.log-* --days 7"
#!/usr/perl
use strict;
use warnings;
use Data::Dumper;
use Getopt::Long;
my $file;
my ($dir,$type,$days);
GetOptions( 'dir' => \$dir,
'type' => \$type,
'days' => \$days);
foreach my $file (<$dir/$type>){
if (-M $file < $days) {
print "\n Deleting log more than '$days' old:".$file;
unlink $file;
# or die "\n Failed to remove $file";
}
}
exit;
If you insist on using Perl, look into File::Find & friends. Though if you're on a *nix box you should probably be aware of find(1) for tasks this common.
try: find /release/logs -name test.log-\* -mtime +7 -delete
If you want to test it out 1st, leave off the -delete flag & it will just print a list of the files it would have otherwise deleted.

Display Output In Browser Perl CGI SSH

I'm executing remote commands using Net::OpenSSH using a web frontend. My commands return without failure on the command line, but I get nothing in a web browser. I've done a couple hour research to no avail--any ideas?
Here is some code to give you an example (some removed for obvious reasons).
#!/usr/bin/perl -w
use strict;
use CGI ':standard';
use Net::OpenSSH;
# Here in the code is just the header and standard tags
print "1";
print "2"; # both display
my $ssh = Net::OpenSSH->new($host, user => $uname, key_path => $key); # all works
$ssh- error and die "Can't ssh to host" . $ssh->error;
print "3";
$ssh->system("uname -a") or
die "remote command failed: " . $ssh->error;
my #lsa = $ssh->capture("ls -a");
$ssh->error and
die "remote ls command failed: ". $ssh->error;
print "4";
print "5";
print #lsa; # won't display in browser, just terminal/CLI
Cheers!
I maintain CGI.pm. I recommend these additions to your simple script:
Before you print anything else, print the standard HTTP header: print header();
Add this after the use CGI line: use CGI::Carp qw(fatalsToBrowser); ... that will display any run-time problems in the browser. If you don't get any output after these changes, check that the script compiles with perl -cw script.pl
Below is about the minimum Perl code that worked for me on Debian machine. I suggest you go through it and compare it to your actual code.
However, it did not work out-of-the box on my Debian, I had make some decisions most of which probably aren't very safe, but that's more about specific environment:
make home for user that server runs writable (/var/www)
add host to ~/.ssh/known_hosts beforehand
use the strict_mode => 0 to bypass Net::OpenSSH's security checks instead of finding proper
ctl_dir (Net::OpenSSH requires that the folder and all above folders are 0755 or more strict,
so /tmp I used is normally not good enough)
I believe there are much safer practices than that, but as I said, that's specific to environment.
So the code:
#!/usr/bin/perl
use strict;
use warnings;
use Net::OpenSSH;
use File::Temp qw/ tempdir /;
# necessary minimum for CGI
print "Content-type: text/plain\n\n";
# prepare temp dir
my $temp = tempdir("/tmp/sshme.pl-XXXXXXXX", CLEANUP => 1);
# open SSH session
my %opts = (
user => "user",
password => "password",
ctl_dir => $temp,
strict_mode => 0 ## NOT recommended - see my comments
);
my $ssh = Net::OpenSSH->new("host", %opts);
$ssh->error
and die "Couldn't establish SSH connection: ". $ssh->error;
# perform command and print output
my #lines = $ssh->capture("ls")
or die "remote command failed: " . $ssh->error;
print #lines;
Perhaps your errors get directed to standard error, not standard output. In that case, they'll usually end up in the server log, not the browser window. Perhaps you can use POSIX::dup2 to avoid this:
use POSIX;
# Make sure to send HTTP headers before redirecting streams!
POSIX::close(2); # close original stderr stream. No more output to apache logs!!!
POSIX::dup2(1,2); # redirect error stream to standard output, so errors will appear in browser.
Processes launched by perl, like e.g. some ssh binary, will inherit these streams.

BioPerl & CPAN - Problems in installation & error "Can't locate Bio/EnsEMBL/Registry.pm in #INC"

I'm posting this message out of pure desperation, because I really don't know what else to try. I'm a beginner in bioperl and I'm working on a script to parse out some results I got from MolQuest fgenesh. Results are out in .txt format and I want to parse them to GFF and fasta file for mRNA and protein sequences to facilitate comparison with other results we have. So I found the Bio::Tools::Fgenesh module and I'm working on a script with it. Problem is, BioPerl doesn't seem to work on my ubuntu pc
I followed the instructions here http://www.bioperl.org/wiki/Installing_Bioperl_for_Unix . I managed to install CPAN in root mode (otherwise it wouldn't work) and BioPerl via CPAN. All tests were ok, but when I ran this script to test the installation
use strict;
use warnings;
use Getopt::Long;
use Bio::EnsEMBL::Registry;
my $reg = "Bio::EnsEMBL::Registry";
$reg->load_registry_from_db(
-host => "ensembldb.ensembl.org",
-user => "anonymous"
);
my $db_list=$reg->get_all_adaptors();
my #line;
foreach my $db (#$db_list){
#line = split ('=',$db);
print $line[0]."\n";
}
I got the error: "Can't locate Bio/EnsEMBL/Registry.pm in #INC"
I tried to install BioPerl again via Build.PL, running as root, but still came to the same outcome.
Thanks for your help
Merche
You seem to be attempting to use the Ensembl API. This is not part of the BioPerl distribution. Please see http://www.ensembl.org/info/docs/api/api_installation.html for more information about how to install it. We do not recommend you install this in any of the default Perl library location as the API is heavily tied into the data made in the same release. Ensembl provides 4-5 releases per year so maintaining this can be difficult.
Should you have anymore issues then you can contact the developers. We have an active developers mailing list & a helpdesk. See http://www.ensembl.org/info/about/contact/index.html for more information.
I had ecountered the same error as you, working on a windows 64x. Seems Bio::EnsEMBL::Registry is not recognized on my windows computer.
Following all the ENSEMBL-API instructions, I finally came across a debugging page (http://www.ensembl.org/info/docs/api/debug_installation_guide.html). After running C:\src\ensembl/misc-scripts/ping_ensembl.pl, I got again the same error message as listed above.
According to the PERL API help for windows, I need to run "set PERL5LIB=C:\src\bioperl-1.2.3;C:\src\ensembl\modules;C:\src\ensembl-compara\modules;C:\src\ensembl-variation\modules;C:\src\ensembl-funcgen\modules" from the cmd box. Did that, but error remained the same.
Now I included these paths (C:\src\bioperl-1.2.3;C:\src\ensembl\modules;C:\src\ensembl-compara\modules;C:\src\ensembl-variation\modules;C:\src\ensembl-funcgen\modules) directly in my perl script, and this seems to work. Probably this is not the way to do it, but as long as it works, I'm happy.
See an example script (based on excercises provided by Bert Overduin) below:
#!/usr/bin/perl -w
use lib "C:/src/ensembl/modules";
use lib "C:/src/ensembl/modules/Bio/EnsEMBL";
use lib "C:/src/ensembl-compara/modules/Bio/EnsEMBL/Compara";
use lib "C:/src/ensembl-functgenomics/modules/Bio/EnsEMBL/Funcgen";
use lib "C:/src/ensembl-variation/modules/Bio/EnsEMBL/Variation";
use strict;
use Bio::EnsEMBL::Registry;
my $registry = 'Bio::EnsEMBL::Registry';
$registry->load_registry_from_db(
-host => 'ensembldb.ensembl.org',
-user => 'anonymous',
-verbose => '1'
);
my $slice_adaptor =
Bio::EnsEMBL::Registry->get_adaptor( "human", "core", "slice" );
get a slice on the entire chromosome X
my $chr_slice = $slice_adaptor->fetch_by_region( 'chromosome', '13', 32_889_000, >32_891_000 );
print "#######################################################\n";
print $chr_slice->seq;
Or alternatively:
#!/usr/bin/perl -w
BEGIN{ push #INC,'C:/src/bioperl-live','C:/src/ensembl/modules','C:/src/ensembl-compara/modules','C:/src/ensembl-variation/modules','C:/src/ensembl-functgenomics/modules';};
use strict;
use Bio::EnsEMBL::Registry;
my $registry = 'Bio::EnsEMBL::Registry';
$registry->load_registry_from_db(
-host => 'ensembldb.ensembl.org',
-user => 'anonymous',
-verbose => '1'
);
my $slice_adaptor =
Bio::EnsEMBL::Registry->get_adaptor( "human", "core", "slice" );
get a slice on the entire chromosome X
my $chr_slice = $slice_adaptor->fetch_by_region( 'chromosome', '13', 32_889_000, >32_891_000 );
print "#######################################################\n";
print $chr_slice->seq;