diff options
-rwxr-xr-x | files/checkbackups.pl | 161 | ||||
-rw-r--r-- | manifests/maildir.pp | 1 | ||||
-rw-r--r-- | manifests/mysql.pp | 8 | ||||
-rw-r--r-- | manifests/rdiff.pp | 31 | ||||
-rw-r--r-- | manifests/server.pp | 71 | ||||
-rw-r--r-- | templates/mysql.conf.erb | 4 | ||||
-rw-r--r-- | templates/rdiff.conf.erb | 2 |
7 files changed, 250 insertions, 28 deletions
diff --git a/files/checkbackups.pl b/files/checkbackups.pl new file mode 100755 index 0000000..80fc07f --- /dev/null +++ b/files/checkbackups.pl @@ -0,0 +1,161 @@ +#!/usr/bin/perl -w + +# This script is designed to check a backup directory populated with +# subdirectories named after hosts, within which there are backups of various +# types. +# +# Example: +# /home/backup: +# foo.example.com +# +# foo.example.com: +# rdiff-backup .ssh +# +# rdiff-backup: +# root home rdiff-backup-data usr var +# +# There are heuristics to determine the backup type. Currently, the following +# types are supported: +# +# rdiff-backup: assumes there is a rdiff-backup/rdiff-backup-data/backup.log file +# duplicity: assumes there is a dup subdirectory, checks the latest file +# dump files: assumes there is a dump subdirectory, checks the latest file +# +# This script returns output suitable for send_nsca to send the results to +# nagios and should therefore be used like this: +# +# checkbackups.sh | send_nsca -H nagios.example.com + +use Getopt::Std; + +# XXX: taken from utils.sh from nagios-plugins-basic +my $STATE_OK=0; +my $STATE_WARNING=1; +my $STATE_CRITICAL=2; +my $STATE_UNKNOWN=3; +my $STATE_DEPENDENT=4; + +# gross hack: we look into subdirs to find vservers +my @vserver_dirs = qw{/var/lib/vservers /vservers}; + +our $opt_d = "/backup"; +our $opt_c = 48 * 60 * 60; +our $opt_w = 24 * 60 * 60; +our $opt_v = 0; +our $opt_o; + +if (!getopts('d:c:w:vo')) { + print <<EOF +Usage: $0 [ -d <backupdir> ] [ -c <threshold> ] [ -w <threshold> ] [ -o ] [ -v ] +EOF + ; + exit(); +} + +my $backupdir= $opt_d; +my $crit = $opt_c; +my $warn = $opt_w; + +my @hosts; +if (defined($opt_o)) { + @hosts=qx{hostname -f}; +} else { + # XXX: this should be a complete backup registry instead + @hosts=qx{ls $backupdir}; +} + +chdir($backupdir); +my ($state, $message, @vservers, $host); +foreach $host (@hosts) { + chomp($host); + if ($opt_o) { + $dir = $backupdir; + } else { + $dir = $host; + } + my $flag=""; + my $type="unknown"; + my $extra_msg=""; + @vservers = (); + $state = $STATE_UNKNOWN; + $message = "???"; + if (-d $dir) { + # guess the backup type and find a proper stamp file to compare + # XXX: the backup type should be part of the machine registry + my $last_bak; + if (-d "$dir/rdiff-backup") { + $flag="$dir/rdiff-backup/rdiff-backup-data/backup.log"; + $type="rdiff"; + if (open(FLAG, $flag)) { + while (<FLAG>) { + if (/StartTime ([0-9]*).[0-9]* \((.*)\)/) { + $last_bak = $1; + $extra_msg = ' [backup.log]'; + $opt_v && print STDERR "found timestamp $1 ($2) in backup.log\n"; + } + } + if (!$last_bak) { + $message = "cannot parse backup.log for a valid timestamp"; + next; + } + } else { + $opt_v && print STDERR "cannot open backup.log\n"; + } + close(FLAG); + foreach my $vserver_dir (@vserver_dirs) { + $vsdir = "$dir/rdiff-backup$vserver_dir"; + if (opendir(DIR, $vsdir)) { + @vservers = grep { /^[^\.]/ && -d "$vsdir/$_" } readdir(DIR); + $opt_v && print STDERR "found vservers $vsdir: @vservers\n"; + closedir DIR; + } else { + $opt_v && print STDERR "no vserver in $vsdir\n"; + } + } + } elsif (-d "$dir/dump") { + # XXX: this doesn't check backup consistency + $flag="$dir/dump/" . `ls -tr $dir/dump | tail -1`; + chomp($flag); + $type="dump"; + } elsif (-d "$dir/dup") { + # XXX: this doesn't check backup consistency + $flag="$dir/dup/" . `ls -tr $dir/dup | tail -1`; + chomp($flag); + $type="dup"; + } elsif (-r "$dir/rsync.log") { + # XXX: this doesn't check backup consistency + $flag="$dir/rsync.log"; + $type="rsync"; + } else { + $message = "unknown system"; + next; + } + if (!defined($last_bak)) { + my @stats = stat($flag); + if (not @stats) { + $message = "cannot stat flag $flag"; + next; + } + $last_bak = $stats[9]; + } + my $t = time(); + my $delta = $t - $last_bak; + if ($delta > $crit) { + $state = $STATE_CRITICAL; + } elsif ($delta > $warn) { + $state = $STATE_WARNING; + } elsif ($delta >= 0) { + $state = $STATE_OK; + } + $message = "$delta seconds old$extra_msg"; + } else { + $message = "no directory"; + } +} continue { + printf "$host\tbackups\t$state\t$message\n"; + my @dom_sufx = split(/\./, $host); + my $dom_sufx = join('.', @dom_sufx[1,-1]); + foreach my $vserver (@vservers) { + printf "$vserver.$dom_sufx\tbackups\t$state\t$message, same as parent: $host\n"; + } +} diff --git a/manifests/maildir.pp b/manifests/maildir.pp index d871654..1427af1 100644 --- a/manifests/maildir.pp +++ b/manifests/maildir.pp @@ -38,4 +38,5 @@ define backupninja::maildir( mode => 0600, require => File["${backupninja::client::defaults::configdir}"] } + package { rsync: ensure => installed } } diff --git a/manifests/mysql.pp b/manifests/mysql.pp index e6cfe90..83d8f8f 100644 --- a/manifests/mysql.pp +++ b/manifests/mysql.pp @@ -17,9 +17,15 @@ define backupninja::mysql( $order = 10, $ensure = present, $user = false, $dbusername = false, $dbpassword = false, $dbhost = 'localhost', $databases = 'all', $backupdir = false, $hotcopy = false, - $sqldump = false, $compress = false, $configfile = '/etc/mysql/debian.cnf', + $sqldump = false, $compress = false, $configfile = true, $vsname = false) { + + $real_configfile = $configfile ? { + true => "/etc/mysql/debian.cnf", + default => $configfile, + } + include backupninja::client::defaults file { "${backupninja::client::defaults::configdir}/${order}_${name}.mysql": ensure => $ensure, diff --git a/manifests/rdiff.pp b/manifests/rdiff.pp index b32a262..1d171b2 100644 --- a/manifests/rdiff.pp +++ b/manifests/rdiff.pp @@ -16,21 +16,25 @@ # directories. # define backupninja::rdiff( - $order = 90, $ensure = present, $user = false, $directory = false, $host = false, + $order = 90, $ensure = present, $user = false, $home = false, $host = false, $type = 'local', $exclude = [ "/home/*/.gnupg", "/home/*/.local/share/Trash", "/home/*/.Trash", "/home/*/.thumbnails", "/home/*/.beagle", "/home/*/.aMule", "/home/*/gtk-gnutella-downloads" ], $include = [ "/var/spool/cron/crontabs", "/var/backups", "/etc", "/root", "/home", "/usr/local/*bin", "/var/lib/dpkg/status*" ], - $vsinclude = false, $keep = 30, $sshoptions = false, $options = false, $ssh_dir_manage = true, - $ssh_dir = false, $authorized_keys_file = false, $installuser = true, $installkey = true, - $backuptag = false, $home = false, $backupkeytype = "rsa", $backupkeystore = false) + $vsinclude = false, $keep = 30, $sshoptions = false, $options = '--force', $ssh_dir_manage = true, + $ssh_dir = false, $authorized_keys_file = false, $installuser = true, $installkey = true, $key = false, + $backuptag = false, $home = false, $backupkeytype = "rsa", $backupkeystore = false, $extras = false) { + $real_backuptag = $backuptag ? { + false => "backupninja-$host", + default => $backuptag + } + + $directory = "$home/rdiff-backup/" include backupninja::client::defaults - case $directory { false: { err("need to define a directory for where the backups should go!") } } - case $type { 'remote': { case $host { false: { err("need to define a host for remote backups!") } } @@ -42,10 +46,10 @@ define backupninja::rdiff( backupninja::server::sandbox { - "${user}-${name}": user => $user, host => $host, dir => $real_home, - manage_ssh_dir => $ssh_dir_manage, ssh_dir => $ssh_dir, + "${user}-${name}": user => $user, host => $fqdn, dir => $home, + manage_ssh_dir => $ssh_dir_manage, ssh_dir => $ssh_dir, key => $key, authorized_keys_file => $authorized_keys_file, installuser => $installuser, - backuptag => $backuptag, keytype => $backupkeytype, backupkeys => $backupkeystore, + backuptag => $real_backuptag, keytype => $backupkeytype, backupkeys => $backupkeystore, } backupninja::client::key @@ -65,5 +69,14 @@ define backupninja::rdiff( mode => 0600, require => File["${backupninja::client::defaults::configdir}"] } + include backupninja::rdiff-installed +} + +class backupninja::rdiff-installed { + case $lsbdistcodename { + "etch": { $version = "1.2.5-1~bpo40+1" } + default: { $version = "installed" } + } + package { "rdiff-backup": ensure => $version } } diff --git a/manifests/server.pp b/manifests/server.pp index 790c931..52cb11c 100644 --- a/manifests/server.pp +++ b/manifests/server.pp @@ -23,18 +23,36 @@ class backupninja::server { mode => 0710, owner => root, group => "backupninjas" } + file { "/usr/local/bin/checkbackups": + ensure => "present", + source => "puppet://$servername/backupninja/checkbackups.pl", + mode => 0755, owner => root, group => root, + } + + cron { checkbackups: + command => "/usr/local/bin/checkbackups -d $real_backupdir | /usr/sbin/send_nsca -H nagios.koumbit.net -c /etc/send_nsca.cfg | grep -v 'sent to host successfully'", + user => "root", + hour => "8-23", + minute => 59, + require => [ File["/usr/local/bin/checkbackups"], Package['nsca'] ] + } + User <<| tag == "backupninja-$real_backupserver_tag" |>> File <<| tag == "backupninja-$real_backupserver_tag" |>> + Ssh_authorized_key <<| tag == "backupninja-$real_backupserver_tag" |>> + + package { "rsync": ensure => installed } + include backupninja::rdiff-installed # this define allows nodes to declare a remote backup sandbox, that have to # get created on the server define sandbox( $user = false, $host = false, $installuser = true, $dir = false, $manage_ssh_dir = true, - $ssh_dir = false, $authorized_keys_file = false, $backupkeys = false, $keytype = "rsa", - $uid = false, $gid = "backupninjas", $backuptag = false) + $ssh_dir = false, $authorized_keys_file = false, $key = false, $keytype = 'dss', $backupkeys = false, $uid = false, + $gid = "backupninjas", $backuptag = false) { - $real_user = $name ? { + $real_user = $user ? { false => $name, default => $user, '' => $name, @@ -63,11 +81,14 @@ class backupninja::server { false => "backupninja-$real_host", default => $backuptag, } - + + # configure a passive service check for backups + nagios2::passive_service { "backups-$real_host": nagios2_host_name => $real_host, nagios2_description => 'backups', servicegroups => "backups" } + if !defined(File["$real_dir"]) { @@file { "$real_dir": ensure => directory, - mode => 0750, owner => $user, group => 0, + mode => 0750, owner => $real_user, group => 0, tag => "$real_backuptag", } } @@ -78,22 +99,36 @@ class backupninja::server { if !defined(File["$real_ssh_dir"]) { @@file { "${real_ssh_dir}": ensure => directory, - mode => 0700, owner => $user, group => 0, - require => File["$real_dir"], + mode => 0700, owner => $real_user, group => 0, + require => [User[$real_user], File["$real_dir"]], tag => "$real_backuptag", } } } } - if !defined(File["${real_ssh_dir}/${real_authorized_keys_file}"]) { - @@file { "${real_ssh_dir}/${real_authorized_keys_file}": - ensure => present, - mode => 0644, owner => 0, group => 0, - source => "$real_backupkeys/${user}_id_${keytype}.pub", - require => File["${real_ssh_dir}"], - tag => "$real_backuptag", + case $key { + false: { + if !defined(File["${real_ssh_dir}/${real_authorized_keys_file}"]) { + @@file { "${real_ssh_dir}/${real_authorized_keys_file}": + ensure => present, + mode => 0644, owner => 0, group => 0, + source => "$real_backupkeys/${real_user}_id_${keytype}.pub", + require => File["${real_ssh_dir}"], + tag => "$real_backuptag", + } + } + } + default: { + @@ssh_authorized_key{ $real_user: + type => $key_type, + key => $key, + user => $real_user, + target => "${real_ssh_dir}/${real_authorized_keys_file}", + tag => "$real_backuptag", + require => User[$real_user], + } } - } + } case $uid { false: { if !defined(User["$real_user"]) { @@ -105,13 +140,13 @@ class backupninja::server { managehome => true, shell => "/bin/sh", password => '*', - require => Group['backupninjas'], + require => Group['backupninjas'], tag => "$real_backuptag" } } } default: { - if !defined(User["$real_user"]) { + if !defined(User["$real_user"]) { @@user { "$real_user": ensure => "present", uid => "$uid", @@ -121,7 +156,7 @@ class backupninja::server { managehome => true, shell => "/bin/sh", password => '*', - require => Group['backupninjas'], + require => Group['backupninjas'], tag => "$real_backuptag" } } diff --git a/templates/mysql.conf.erb b/templates/mysql.conf.erb index 9d22ab0..14905fd 100644 --- a/templates/mysql.conf.erb +++ b/templates/mysql.conf.erb @@ -12,3 +12,7 @@ end -%> hotcopy = <%= hotcopy ? 'yes' : 'no' %> sqldump = <%= sqldump ? 'yes' : 'no' %> compress = <%= compress ? 'yes' : 'no' %> + +<% if real_configfile %> +configfile = <%= real_configfile %> +<% end %> diff --git a/templates/rdiff.conf.erb b/templates/rdiff.conf.erb index a41e969..23c336f 100644 --- a/templates/rdiff.conf.erb +++ b/templates/rdiff.conf.erb @@ -5,6 +5,8 @@ <%= 'options = ' + options if options %> +<%= extras if extras %> + [source] type = local <%= 'keep = ' + keep if keep %> |