package Smokeping::probes::FTPtransfer; =head1 301 Moved Permanently This is a Smokeping probe module. Please use the command C to view the documentation or the command C to generate the POD document. =cut use strict; use base qw(Smokeping::probes::passwordchecker); use Net::FTP; use Time::HiRes qw(gettimeofday sleep); use Carp; my $DEFAULTINTERVAL = 1; sub pod_hash { return { name => < < < as it transfers real data. By using real data we get a fair shot at figuring out what a link is capable of when it comes to transfering actual files. The password can be specified either (in order of precedence, with the latter overriding the former) in the probe-specific variable `password', in an external file or in the target-specific variable `password'. The location of this external file is given in the probe-specific variable `passwordfile'. See Smokeping::probes::passwordchecker(3pm) for the format of this file (summary: colon-separated triplets of the form `::') The probe tries to be nice to the server and waits at least X seconds between starting filetransfers, where X is the value of the probe specific `min_interval' variable ($DEFAULTINTERVAL by default). Many variables can be specified either in the probe or in the target definition, the target-specific variable will override the prove-specific variable. If your transfer takes a lot of time, you may want to make sure to set the B and B properly so that smokeping does not abort the transfers of limit the graph size. DOC authors => <<'DOC', Tobias Oetiker sponsored by Virtela DOC bugs => < is at the core of the application. It would take some re-engineering to split this out in plugins and thus make it configurable ... DOC } } # returns the last part of a path sub _get_filename ($) { return (split m|/|, $_[0])[-1]; } sub ProbeDesc ($) { my $self = shift; my $srcfile = $self->{properties}{srcfile}; my $destfile = $self->{properties}{destfile} || _get_filename $self->{properties}{srcfile}; my $mode = $self->{properties}{mode}; my $size = $mode eq 'get' ? -s $destfile : -s $srcfile; return sprintf("FTP File transfers (%.0f KB)",$size/1024); } sub new { my $proto = shift; my $class = ref($proto) || $proto; my $self = $class->SUPER::new(@_); return $self; } sub pingone { my $self = shift; my $target = shift; my $host = $target->{addr}; my $vars = $target->{vars}; my $mininterval = $self->{properties}{min_interval}; my $srcfile = $self->{properties}{srcfile}; my $destfile = $self->{properties}{destfile} || _get_filename $self->{properties}{srcfile}; my $mode = $self->{properties}{mode}; my $username = $vars->{username}; $self->do_log("Missing FTP username for $host"), return unless defined $username; my $password = $self->password($host, $username) || $vars->{password}; $self->do_log("Missing FTP password for $host/$username"), return unless defined $password; my @options = (); push (@options, Timeout => $vars->{timeout}); push (@options, Port => $vars->{port} ) if $vars->{port}; push (@options, LocalAddr => $vars->{localaddr} ) if $vars->{localaddr}; push (@options, Passive => 1 ) if $vars->{passive} and $vars->{passive} eq 'yes'; my @times; my $elapsed; for (1..$self->pings($target)) { if (defined $elapsed) { my $timeleft = $mininterval - $elapsed; sleep $timeleft if $timeleft > 0; } my $ftp = Net::FTP->new($host, @options) or $self->do_log("Problem with $host: ftp session $@"), return; $ftp->login($username,$password) or $self->do_log("Problem with $host: ftp login ".$ftp->message), return; my $start = gettimeofday(); my $ok; my $size; if ($mode eq 'get'){ $ok = $ftp->get($srcfile,$destfile) or $self->do_log("Problem with $host: ftp get ".$ftp->message); $size = -s $destfile; } else { $ok = $ftp->put($srcfile,$destfile) or $self->do_log("Problem with $host: ftp put ".$ftp->message); $size = -s $srcfile; } my $end = gettimeofday(); $ftp->quit; $elapsed = ( $end - $start ); $ok or next; $self->do_debug("$host - $mode mode transfered $size Bytes in ${elapsed}s"); push @times, $elapsed; } return sort { $a <=> $b } @times; } sub probevars { my $class = shift; my $h = $class->SUPER::probevars; delete $h->{timeout}{_default}; # force a timeout to be defined $h->{timeout}{_doc} = <_makevars($h, { _mandatory => [ 'srcfile','mode','timeout' ], srcfile => { _doc => < mode, this file has to be on the local machine, if the probe is in B mode then this file should sit in the remote ftp account. DOC _example => 'src/path/mybig.pdf', }, destfile => { _doc => < 'path/to/destinationfile.xxx', }, mode => { _doc => < 'get', _re => '(put|get)', }, min_interval => { _default => $DEFAULTINTERVAL, _doc => "The minimum interval between each starting ftp sessions in seconds.", _re => '(\d*\.)?\d+', }, }); } sub targetvars { my $class = shift; return $class->_makevars($class->SUPER::targetvars, { username => { _doc => 'The username to be tested.', _example => 'test-user', }, password => { _doc => 'The password for the user, if not present in the password file.', _example => 'test-password', }, timeout => { _doc => "Timeout in seconds for the FTP transfer to complete.", _re => '\d+', _example => 10, }, port => { _doc => 'A non-standard FTP port to be used', _re => '\d+', _example => '3255', }, localaddr => { _doc => 'The local address to be used when making connections', _example => 'myhost-nat-if', }, passive => { _doc => 'Use passive FTP protocol', _re => '(yes|no)', _example => 'yes', } }); } 1;