scp-on-xferlog.pl
Dieses Programm verabschiedet sich direkt nach dem Start in den Hintergrund (Dämon) und schaut dann auf Veränderungen im File /var/log/xferlog. Wird nun via FTP eine Datei hochgeladen, wird sie via SCP (passwortloses Login via Keys sollte vorher natürlich eingerichtet sein) auf die Server in @hosts kopiert. Dies ist z.B. nützlich wenn man mehrere Server in einem Loadbalancingcluster betreibt.
#!/usr/bin/perl
#
# 2008 Oliver Voelker <wiki(at)magenbrot.net>
#
# Dieses Script lauscht auf neue Eintraege in /var/log/xferlog und kopiert neu hochgeladene Dateien
# mit einer Verzoegerung von max. etwa 1-5 Sekunden auf die konfigurierten Hosts.
#
use strict;
use warnings;
use File::Tail;
use File::Basename;
use POSIX qw(setsid);
my $debug = 1; # 1 = normal, 2 = extended logging
my $name = "/var/log/xferlog"; # watch this file
#my $logfile = "/dev/null"; # logfile
my $logfile = "/var/log/scp-on-xferlog"; # logfile
my @hosts = ("host1.de", "host2.de", "host3.de"); # list of hosts
# don't edit anything below this line
my $line = "";
sub daemonize {
chdir("/") or die("Can't chdir to /: $!");
open(STDIN, "/dev/null") or die("Can't read /dev/null: $!");
open(STDOUT, ">>$logfile") or die("Can't write to $logfile: $!");
open(STDERR, ">>$logfile") or die("Can't write to $logfile: $!");
defined(my $pid = fork) or die("Can't fork: $!");
exit if($pid);
setsid or die("Can't start a new session: $!");
umask(0);
}
sub sharefile {
my ($host,$file) = @_;
my $try = 0;
my $error = 1;
until ($error eq "" || $try == 5) {
print localtime(time) . " Trans: $host" if($debug);
system ("scp -1 \"$file\" root\@$host:$file >/dev/null 2>&1");
if ($? != 0 && $try eq 0) {
my $dirname = dirname($file);
print " - Error: Creating non-existent directory: $dirname\n" if ($debug >=2);
system ("ssh -1 root\@$host \"mkdir -p $dirname\" >/dev/null 2>&1");
system ("scp -1 \"$file\" root\@$host:$file >/dev/null 2>&1");
$try++;
} elsif ($? != 0 && $try >= 0) {
$error=$error . " " . $host;
print " - failed: $!\n" if ($debug);
sleep 2;
$try++;
}
else {
print " - ok\n" if ($debug);
$error="";
}
}
return $error;
}
# flush the buffer
$| = 1;
# daemonize the program
&daemonize;
my $log = File::Tail->new(name => $name, maxinterval => 5, adjustafter => 10);
while (defined($line = $log->read)) {
my (undef, undef, undef, undef, undef, undef, undef, undef, $file) = split(/ /, $line);
my $count = 0;
my $error = "1";
until (-f $file || $count eq 5) {
# we'll wait max 5*2 seconds for the transfer of the file to complete
print localtime(time) . "Info: File does not exist yet: $file\n";
sleep 2;
$count++;
}
my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,$blksize,$blocks)=stat($file) if ($debug >= 2);
print localtime(time) . "File: $file Size: $size Access: " . scalar localtime($atime) . " Modified: " . scalar localtime($mtime) . "\n" if ($debug >= 2);
# copy files
foreach (@hosts) {
$error=sharefile($_,$file);
}
if ($error eq "") {
print localtime(time) . " Shared: $file\n" if ($debug);
} else {
print localtime(time) . " Error: $file was not copied to: $error\n";
}
}
nützlich ist dann noch das Initscript, welches sich um den Start des Dämons beim Booten kümmert:
#!/bin/bash
#
# scp-on-xferlog Starts scp-on-xferlog.
#
#
# chkconfig: 2345 12 88
# description: scp-on-xferlog is used to copy new transferred files (from xferlog) to other configured hosts
#
### BEGIN INIT INFO
# Provides: $scp-on-xferlog
### END INIT INFO
# Source function library.
. /etc/init.d/functions
[ -f /usr/local/sbin/scp-on-xferlog.pl ] || exit 0
RETVAL=0
start() {
echo -n $"Starting scp-on-xferlog: "
daemon /usr/local/sbin/scp-on-xferlog.pl
RETVAL=$?
echo
[ $RETVAL -eq 0 ] && touch /var/lock/subsys/scp-on-xferlog
return $RETVAL
}
stop() {
echo -n $"Shutting down scp-on-xferlog: "
killproc scp-on-xferlog.pl
echo
RETVAL=$?
[ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/scp-on-xferlog
return $RETVAL
}
rhstatus() {
status scp-on-xferlog.pl
}
restart() {
stop
start
}
case "$1" in
start)
start
;;
stop)
stop
;;
status)
rhstatus
;;
restart)
restart
;;
*)
echo $"Usage: $0 {start|stop|status|restart}"
exit 1
esac
exit $?
und die Datei für's Logrotate:
/var/log/scp-on-xferlog {
daily
missingok
notifempty
postrotate
/etc/init.d/scp-on-xferlog restart
endscript
}