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

Hello,

this script has as purpose to daily download a file to a local folder.. the time of the upload is not known so it will run in a cron every four hours. the problem is that the script dies with error if there is no file in the local folder but also not yet in the remote (sftp folder)...is there a way to differentiate if the file does not (yet) exist and that it exists but the tranfer has failed? <\p> I also would need to monitor the status of the transfer with nagios..if the transfer fails I would need to send it to a nagios system with nsca.. in bash I would do something like: echo -e "...."| send_nsca... how can i integrate that in perl.

#!/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.brusselsairlines.com"; my $username="dlex"; my $local="/mnt/datalex"; my $file="BookingReport_Daily_$datestring.xls"; my $sftp = Net::SFTP::Foreign->new($host, user=> $username, stderr_dis +card => 1 ); $sftp->die_on_error("unable to establish SFTP Connection"); my $ok = 0; my $failed = 0; if ( -e "$local/$file"){ print "File \"$file\" has already been Downloaded to ==> \"$lo +cal\"\n" } else { if ($sftp->get("$file", "$local/$file")) { print "File \"$file\" downloaded to ==> \"$local\"\n"; $sftp->remove($file); $ok++; } else { print "Unable to download file \"$file\" : " . $sftp-> +error . "\n"; $failed++; } } print "$ok files have been downloaded, $failed files failed!\n\n"; $sftp->disconnect();
thank you Mario

Replies are listed 'Best First'.
Re: net-sftp-foreign transfer failed vs file not present.
by salva (Canon) on Aug 06, 2014 at 15:45 UTC
    If the remote file doesn't exist, get fails and the error code becomes SFTP_ERR_REMOTE_STAT_FAILED or SFTP_ERR_REMOTE_OPEN_FAILED (constants are defined in Net::SFTP::Foreign::Constants).

    You can also check the last status response from the server ($sftp->status). For conforming serves, that should be SSH2_FX_NO_SUCH_FILE.

    In summary:

    use Net::SFTP::Foreign::Constants qw(:error :status); ... unless ($sftp->get($remote, $local)) { if (($sftp->error == SFTP_ERR_REMOTE_STAT_FAILED or $sftp->error == SFTP_ERR_REMOTE_OPEN_FAILED) and $sftp->status == SSH2_FX_NO_SUCH_FILE) { say "Remote file does not exist!"; } else { say "Transfer failed"; } die $sftp->error; }

      Hello

      thank you for your input. I modified the script accordingly but still gives me this error: Uncaught exception from user code: Couldn't stat remote file: No such file at ./datalex.pl line 37. here is my script with the code adapted:
      #!/usr/bin/perl -w use strict; use warnings; use Net::SFTP::Foreign; use POSIX qw(strftime); use diagnostics; use Net::SFTP::Foreign::Constants qw(:error :status); my $datestring =strftime "%d-%m-%Y", localtime; my $host="sftp.brusselsairlines.com"; my $username="dlex"; my $local="/mnt/datalex"; my $file="BookingReport_Daily_$datestring.xls"; #nagios integration. my $sftp = Net::SFTP::Foreign->new($host, user=> $username, stderr_dis +card => 1 ); $sftp->die_on_error("unable to establish SFTP Connection"); my $ok = 0; my $failed = 0; if ( -e "$local/$file"){ print "BH-ZONE-BATCHSRV-1\tfoster_report_transfer\t0\tFile \" +$file\" has already been Downloaded to ==> \"$local\"\n"; } else { unless ($sftp->get("$file", "$local/$file")) { if (($sftp->error == SFTP_ERR_REMOTE_STAT_FAILED or $sftp->error == SFTP_ERR_REMOTE_OPEN_FAILED) and $sftp->status == SSH2_FX_NO_SUCH_FILE) { print "Remote file does not exist!"; } else { print "Transfer Failed"; } die $sftp->error; } print "File \"$file\" downloaded to ==> \"$local\"\n"; $sftp->remove($file); $ok++; } #print "$ok files have been downloaded, $failed files failed!\n\n"; $sftp->disconnect();
      perhaps i should use $sftp->ls to get the filename but I do not understand how to get the name of the file in a variable.. i do not understand the hash reference. i try this but it does not work. .
      my $ls = $sftp->ls( '.', wanted => qr/$datestring/) or die "unable to + retrieve directory: ".$sftp->error; my $file = "$_->{filename}\n" for (@$ls); print $file
      thanks

        Hi,

        I've just seen that your problem isn't solved yet, is it?

        You get an exception, but this is what you've coded:

        unless ($sftp->get("$file", "$local/$file")) { if (($sftp->error == SFTP_ERR_REMOTE_STAT_FAILED or $sftp->error == SFTP_ERR_REMOTE_OPEN_FAILED) and $sftp->status == SSH2_FX_NO_SUCH_FILE) { print "Remote file does not exist!"; } else { print "Transfer Failed"; } die $sftp->error; }

        Independent from your if-clause you have a die at the end of your conditional block when get didn't work. More interesting would be to see whether you get the line "Remote file does not exist!".

        Where does the message "Uncaught exception from user code: Couldn't stat remote file: No such file at ./datalex.pl line 37" come from? A wrapper?

        Regards
        McA

Re: net-sftp-foreign transfer failed vs file not present.
by McA (Priest) on Aug 06, 2014 at 15:15 UTC

    Hi,

    one possiblity would be to check whether the file exists on the remote server via $sftp->ls($remote, %opts). You must be aware that this introduces a race condition, because between lookup and download it's possible that the file vanishes. The second possibility is to check the error message / exception for the error condition and react accordingly.

    To your problem with sending stuff via send_nsca:

    open my $fh, "|-", "send_nsca" or die "Arggghh, couldn't open pipe to +send_nsca: $!"; print $fh "All you want to send to STDIN of send_nsca"; close $fh or die "Something bad happended while piping to send_nsca: $ +!";

    Regards
    McA