From 2435f6b2884f11b1d562c18f360264d3eb455f47 Mon Sep 17 00:00:00 2001 From: Jamie McClelland Date: Tue, 15 Mar 2011 21:14:24 -0400 Subject: provide pgsql support --- manifests/init.pp | 1 + manifests/pgsql.pp | 29 +++++++++++++++++++++++++++++ templates/pgsql.conf.erb | 11 +++++++++++ 3 files changed, 41 insertions(+) create mode 100644 manifests/pgsql.pp create mode 100644 templates/pgsql.conf.erb diff --git a/manifests/init.pp b/manifests/init.pp index 23b4268..fba8cc4 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -4,6 +4,7 @@ import "dup.pp" import "labelmount.pp" import "maildir.pp" import "mysql.pp" +import "pgsql.pp" import "rdiff.pp" import "server.pp" import "sh.pp" diff --git a/manifests/pgsql.pp b/manifests/pgsql.pp new file mode 100644 index 0000000..19fd46b --- /dev/null +++ b/manifests/pgsql.pp @@ -0,0 +1,29 @@ +# Safe PGSQL dumps, as part of a backupninja run. +# +# Valid attributes for this type are: +# +# order: The prefix to give to the handler config filename, to set +# order in which the actions are executed during the backup run. +# +# ensure: Allows you to delete an entry if you don't want it any more +# (but be sure to keep the configdir, name, and order the same, so +# that we can find the correct file to remove). +# +# backupdir, compress, configfile: As defined in the +# backupninja documentation, with the caveat that hotcopy, sqldump, +# and compress take true/false rather than yes/no. +# +define backupninja::pgsql( + $order = 10, $ensure = present, $databases = 'all', $backupdir = "/var/backup/postgres", $compress = true, $vsname = false) +{ + + include backupninja::client::defaults + file { "${backupninja::client::defaults::configdir}/${order}_${name}.pgsql": + ensure => $ensure, + content => template('backupninja/pgsql.conf.erb'), + owner => root, + group => root, + mode => 0600, + require => File["${backupninja::client::defaults::configdir}"] + } +} diff --git a/templates/pgsql.conf.erb b/templates/pgsql.conf.erb new file mode 100644 index 0000000..7781ef4 --- /dev/null +++ b/templates/pgsql.conf.erb @@ -0,0 +1,11 @@ +<% if vsname %> +vsname = <%= vsname %> +<% end %> +<% if backupdir %> +backupdir = <%= backupdir %> +<% end %> +<% if databases %> +databases = <%= databases %> +<% end %> +compress = <%= compress ? 'yes' : 'no' %> + -- cgit v1.2.3 From a916b07327ea3ac941ae210f697f3b99a17ffb94 Mon Sep 17 00:00:00 2001 From: varac Date: Mon, 29 Oct 2012 19:22:24 +0100 Subject: default: dump to /var/backups/postgres instead of /var/backup/postgres, like the mysql handler --- manifests/pgsql.pp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manifests/pgsql.pp b/manifests/pgsql.pp index 19fd46b..07fab32 100644 --- a/manifests/pgsql.pp +++ b/manifests/pgsql.pp @@ -14,7 +14,7 @@ # and compress take true/false rather than yes/no. # define backupninja::pgsql( - $order = 10, $ensure = present, $databases = 'all', $backupdir = "/var/backup/postgres", $compress = true, $vsname = false) + $order = 10, $ensure = present, $databases = 'all', $backupdir = "/var/backups/postgres", $compress = true, $vsname = false) { include backupninja::client::defaults -- cgit v1.2.3 From 1bceb46bf91c05876edcc0f99a83ea5dbb4f977b Mon Sep 17 00:00:00 2001 From: varac Date: Fri, 30 Nov 2012 11:46:15 +0100 Subject: add backupninja::generate_sshkey --- manifests/generate_sshkey.pp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 manifests/generate_sshkey.pp diff --git a/manifests/generate_sshkey.pp b/manifests/generate_sshkey.pp new file mode 100644 index 0000000..c5e6042 --- /dev/null +++ b/manifests/generate_sshkey.pp @@ -0,0 +1,26 @@ +define backupninja::generate_sshkey( + $ssh_key_basepath = '/etc/puppet/modules/keys/files/backupkeys', +){ + + # generate backupninja ssh keypair + $ssh_key_name = "backup_${::hostname}_id_rsa" + $ssh_keys = ssh_keygen("${ssh_key_basepath}/${ssh_key_name}") + $public = split($ssh_keys[1],' ') + $public_type = $public[0] + $public_key = $public[1] + + # install ssh keypair on client + file { "/root/.ssh/$ssh_key_name": + content => $ssh_keys[0], + owner => root, + group => 0, + mode => '0600'; + } + + file { "/root/.ssh/$ssh_key_name.pub": + content => $public_key, + owner => root, + group => 0, + mode => '0666'; + } +} -- cgit v1.2.3 From d46db38c5346409838d77b24c7f74c1e72cb7caa Mon Sep 17 00:00:00 2001 From: varac Date: Fri, 30 Nov 2012 21:27:14 +0100 Subject: possibilty to create a ssh keypair on the master added following parameters to backupninja::duplicity and backupninja::client::key : $createkey $keystorefspath $keydest $keydestname --- manifests/client.pp | 28 ++++++++++++++++++++++------ manifests/dup.pp | 24 ++++++++++++++++-------- 2 files changed, 38 insertions(+), 14 deletions(-) diff --git a/manifests/client.pp b/manifests/client.pp index 287b02f..3a2755b 100644 --- a/manifests/client.pp +++ b/manifests/client.pp @@ -46,8 +46,10 @@ class backupninja::client::defaults { class backupninja::client inherits backupninja::client::defaults { define key( - $user = false, $host = false, $installkey=false, $keyowner=false, - $keygroup=false, $keystore=false, $keytype=false) + $user = false, $host = false, $createkey=false, $installkey=false, + $keyowner=false, $keygroup=false, $keystore=false, $keystorefspath='', + $keytype=false, + $keydest=false, $keydestname=false ) { $real_user = $user ? { false => $name, @@ -78,9 +80,23 @@ class backupninja::client inherits backupninja::client::defaults { false => "${backupninja::client::defaults::real_keytype}", default => $keytype, } + $key_dest = $keydest ? { + false => "${backupninja::client::defaults::real_keydestination}", + default => $keydest, + } + $key_dest_name = $keydestname ? { + false => "id_$key_type", + default => $keydestname, + } + $key_dest_file = "${key_dest}/${key_dest_name}" - $key_dest = "${backupninja::client::defaults::real_keydestination}" - $key_dest_file = "$key_dest/id_$key_type" + if $createkey == true { + if $keystorefspath == false { + err("need to define a destination directory for sshkey creation!") + } + $ssh_keys = ssh_keygen("${keystorefspath}/${key_dest_name}") + } + case $install_key { true: { @@ -109,7 +125,7 @@ class backupninja::client::maildir inherits backupninja::client::defaults { package { 'rsync': ensure => $rsync_ensure_version, } - } + } } class backupninja::client::rdiff_backup inherits backupninja::client::defaults { @@ -150,4 +166,4 @@ class backupninja::client::sys inherits backupninja::client::defaults { } default: {} } -} +} diff --git a/manifests/dup.pp b/manifests/dup.pp index 23da8cd..5ffce29 100644 --- a/manifests/dup.pp +++ b/manifests/dup.pp @@ -79,7 +79,10 @@ define backupninja::duplicity( $order = 90, $destuser = false, # configs to backupninja client $backupkeystore = false, + $backupkeystorefspath = '', $backupkeytype = "rsa", + $backupkeydest = false, + $backupkeydestname = false, # options to backupninja server sandbox $ssh_dir_manage = true, $ssh_dir = false, @@ -87,6 +90,7 @@ define backupninja::duplicity( $order = 90, $installuser = true, $backuptag = false, # key options + $createkey = false, $installkey = true ) { # the client with configs for this machine @@ -95,7 +99,7 @@ define backupninja::duplicity( $order = 90, case $desthost { false: { err("need to define a destination host for remote backups!") } } case $destdir { false: { err("need to define a destination directory for remote backups!") } } case $password { false: { err("a password is necessary either to unlock the GPG key, or for symmetric encryption!") } } - + # guarantees there's a configured backup space for this backup backupninja::server::sandbox { "${user}-${name}": user => $destuser, @@ -109,14 +113,18 @@ define backupninja::duplicity( $order = 90, backupkeys => $backupkeystore, keytype => $backupkeytype, } - + # the client's ssh key backupninja::client::key { "${destuser}-${name}": - user => $destuser, - host => $desthost, - installkey => $installkey, - keytype => $backupkeytype, - keystore => $backupkeystore, + user => $destuser, + host => $desthost, + createkey => $createkey, + installkey => $installkey, + keytype => $backupkeytype, + keystore => $backupkeystore, + keystorefspath => $backupkeystorefspath, + keydest => $backupkeydest, + keydestname => $backupkeydestname } # the backupninja rule for this duplicity backup @@ -129,4 +137,4 @@ define backupninja::duplicity( $order = 90, require => File["${backupninja::client::defaults::configdir}"] } } - + -- cgit v1.2.3 From 7e731b95d6841a3bcbb38fc5cc8189b87b3c2f0c Mon Sep 17 00:00:00 2001 From: varac Date: Mon, 3 Dec 2012 12:27:34 +0100 Subject: use same name for key creation and deployment --- manifests/client.pp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manifests/client.pp b/manifests/client.pp index 3a2755b..7e689bf 100644 --- a/manifests/client.pp +++ b/manifests/client.pp @@ -108,7 +108,7 @@ class backupninja::client inherits backupninja::client::defaults { } if !defined(File["$key_dest_file"]) { file { "$key_dest_file": - source => "${key_store}/${real_user}_id_${key_type}", + source => "${key_store}/${key_dest_name}", mode => 0400, owner => $key_owner, group => $key_group, require => File["$key_dest"], } -- cgit v1.2.3 From 05126fc24983ec3735eea1d56971aafc5b9c317b Mon Sep 17 00:00:00 2001 From: varac Date: Mon, 21 Jan 2013 21:04:41 +0100 Subject: README:Automatic creation of ssh-keys for duplicity --- README | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/README b/README index 5b7c2c9..a839193 100644 --- a/README +++ b/README @@ -1,7 +1,7 @@ Backupninja Module ------------------- -This module helps you configure all of your backups with puppet, using +This module helps you configure all of your backups with puppet, using backupninja! ! Upgrade notice ! @@ -32,12 +32,12 @@ Configure your backup server Now you will need to configure a backup server by adding the following to your node definition for that server: - + include backupninja::server By configuring a backupninja::server, this module will automatically create sandboxed users on the server for each client for their -backups. +backups. You may also want to set some variables on your backup server, such as: @@ -130,6 +130,33 @@ backupninja::config { conf: } +Automatic creation of ssh-keys for duplicity +-------------------------------------------- + +backupninja::duplicity can be used to + +- create an ssh keypair for a client +- place the keypair on the puppetmaster in a given location +- place the keypair in /root/.ssh on the client + +i.e.: + + backupninja::duplicity { "duplicity_${::fqdn}": + sshoptions => "-oIdentityFile=/root/.ssh/backupninja_${::hostname}_id_rsa", + desthost => 'HOST', + destdir => "/var/backup/backupninja/${::fqdn}", + destuser => "backupninja_${::hostname}", + encryptkey => 'KEYID', + password => 'PW', + backupkeystore => 'puppet:///keys', + backupkeystorefspath => '/etc/puppet/modules/keys/files', + backupkeydestname => "backupninja_${::hostname}_id_rsa", + createkey => true, + installkey => true, + ... + } + + Nagios alerts about backup freshness ------------------------------------ -- cgit v1.2.3 From 1e5db13e9c103b93fcdbd3983099c734358f524c Mon Sep 17 00:00:00 2001 From: varac Date: Thu, 24 Jan 2013 12:08:24 +0100 Subject: check_backupninja_duplicity.py nagios script --- files/nagios_plugins/duplicity/README.md | 24 ++ .../duplicity/backupninja_duplicity_freshness.sh | 268 +++++++++++++++++++++ .../duplicity/check_backupninja_duplicity.py | 118 +++++++++ manifests/nagios_plugin/duplicity.pp | 22 ++ 4 files changed, 432 insertions(+) create mode 100644 files/nagios_plugins/duplicity/README.md create mode 100644 files/nagios_plugins/duplicity/backupninja_duplicity_freshness.sh create mode 100644 files/nagios_plugins/duplicity/check_backupninja_duplicity.py create mode 100644 manifests/nagios_plugin/duplicity.pp diff --git a/files/nagios_plugins/duplicity/README.md b/files/nagios_plugins/duplicity/README.md new file mode 100644 index 0000000..1cd349a --- /dev/null +++ b/files/nagios_plugins/duplicity/README.md @@ -0,0 +1,24 @@ +duplicity-backup-status +======================= + +Backupninja generates duplicity configfiles, this nagios plugin can check their freshness. Currently only the config files generated by backupninja can be parsed and we depend on that. + +## Prerequisites + +Make sure you have python-argparse installed (yes an extra dependency, getopt doubles the amount of code, so I gave up on that). The Python script will look for the duplicity_freshness.sh shell script in /usr/local/lib/nagios/plugins/ or /usr/lib/nagios/plugins/ make sure you copy it there and make executable. + +## Getting started + +Run the python script from your nagios. Don't forget to specify some extras like when warnings or criticalities should be emerged. + +- -w WARNINC Number of hours allowed for incremential backup warning level default 28 +- -W WARNFULL Number of hours allowed for incremential backup critical level default 40 +- -c CRITINC Number of days allowed for full backup warning level default 52 +- -C CRITFULL Number of days allowed for full backup critical level default 60 + + +## TODO: + +- make it cuter, tidy up +- make it more robust +- support other config backends as backupninja - this can be done by writing more scripts like backupninja_duplicity_freshness.sh and parsing an extra parameter diff --git a/files/nagios_plugins/duplicity/backupninja_duplicity_freshness.sh b/files/nagios_plugins/duplicity/backupninja_duplicity_freshness.sh new file mode 100644 index 0000000..ea694d0 --- /dev/null +++ b/files/nagios_plugins/duplicity/backupninja_duplicity_freshness.sh @@ -0,0 +1,268 @@ +# -*- mode: sh; sh-basic-offset: 3; indent-tabs-mode: nil; -*- +# vim: set filetype=sh sw=3 sts=3 expandtab autoindent: + +# Load backupninja library/helpers, because why reinventing the wheel? [Because my wheels weren't round] +# some duplication is to be expected +# this is only supposed to work with duplicity + +## Functions +# simple lowercase function +function tolower() { + echo "$1" | tr '[:upper:]' '[:lower:]' +} + +# we grab the current time once, since processing +# all the configs might take more than an hour. +nowtime=`LC_ALL=C date +%H` +nowday=`LC_ALL=C date +%d` +nowdayofweek=`LC_ALL=C date +%A` +nowdayofweek=`tolower "$nowdayofweek"` + +conffile="/etc/backupninja.conf" + +# find $libdirectory +libdirectory=`grep '^libdirectory' $conffile | /usr/bin/awk '{print $3}'` +if [ -z "$libdirectory" ]; then + if [ -d "/usr/lib/backupninja" ]; then + libdirectory="/usr/lib/backupninja" + else + echo "Could not find entry 'libdirectory' in $conffile." + fatal "Could not find entry 'libdirectory' in $conffile." + fi +else + if [ ! -d "$libdirectory" ]; then + echo "Lib directory $libdirectory not found." + fatal "Lib directory $libdirectory not found." + fi +fi + +. $libdirectory/tools + +setfile $conffile + +# get global config options (second param is the default) +getconf configdirectory /etc/backup.d +getconf scriptdirectory /usr/share/backupninja +getconf reportdirectory +getconf reportemail +getconf reporthost +getconf reportspace +getconf reportsuccess yes +getconf reportinfo no +getconf reportuser +getconf reportwarning yes +getconf loglevel 3 +getconf when "Everyday at 01:00" +defaultwhen=$when +getconf logfile /var/log/backupninja.log +getconf usecolors "yes" +getconf SLAPCAT /usr/sbin/slapcat +getconf LDAPSEARCH /usr/bin/ldapsearch +getconf RDIFFBACKUP /usr/bin/rdiff-backup +getconf CSTREAM /usr/bin/cstream +getconf MYSQLADMIN /usr/bin/mysqladmin +getconf MYSQL /usr/bin/mysql +getconf MYSQLHOTCOPY /usr/bin/mysqlhotcopy +getconf MYSQLDUMP /usr/bin/mysqldump +getconf PGSQLDUMP /usr/bin/pg_dump +getconf PGSQLDUMPALL /usr/bin/pg_dumpall +getconf PGSQLUSER postgres +getconf GZIP /bin/gzip +getconf GZIP_OPTS --rsyncable +getconf RSYNC /usr/bin/rsync +getconf admingroup root + +if [ ! -d "$configdirectory" ]; then + echo "Configuration directory '$configdirectory' not found." + fatal "Configuration directory '$configdirectory' not found." +fi + +# get the duplicity configuration +function get_dupconf(){ + setfile $1 + getconf options + getconf testconnect yes + getconf nicelevel 0 + getconf tmpdir + + setsection gpg + getconf password + getconf sign no + getconf encryptkey + getconf signkey + + setsection source + getconf include + getconf vsnames all + getconf vsinclude + getconf exclude + + setsection dest + getconf incremental yes + getconf increments 30 + getconf keep 60 + getconf keepincroffulls all + getconf desturl + getconf awsaccesskeyid + getconf awssecretaccesskey + getconf cfusername + getconf cfapikey + getconf cfauthurl + getconf ftp_password + getconf sshoptions + getconf bandwidthlimit 0 + getconf desthost + getconf destdir + getconf destuser + destdir=${destdir%/} +} + +### some voodoo to mangle the correct commands + +function mangle_cli(){ + + execstr_options="$options " + execstr_source= + if [ -n "$desturl" ]; then + [ -z "$destuser" ] || warning 'the configured destuser is ignored since desturl is set' + [ -z "$desthost" ] || warning 'the configured desthost is ignored since desturl is set' + [ -z "$destdir" ] || warning 'the configured destdir is ignored since desturl is set' + execstr_serverpart="$desturl" + else + execstr_serverpart="scp://$destuser@$desthost/$destdir" + fi + + + ### Symmetric or asymmetric (public/private key pair) encryption + if [ -n "$encryptkey" ]; then + execstr_options="${execstr_options} --encrypt-key $encryptkey" + fi + + ### Data signing (or not) + if [ "$sign" == yes ]; then + # duplicity is not able to sign data when using symmetric encryption + [ -n "$encryptkey" ] || fatal "The encryptkey option must be set when signing." + # if needed, initialize signkey to a value that is not empty (checked above) + [ -n "$signkey" ] || signkey="$encryptkey" + execstr_options="${execstr_options} --sign-key $signkey" + fi + + ### Temporary directory + precmd= + if [ -n "$tmpdir" ]; then + if [ ! -d "$tmpdir" ]; then + #info "Temporary directory ($tmpdir) does not exist, creating it." + mkdir -p "$tmpdir" + [ $? -eq 0 ] || fatal "Could not create temporary directory ($tmpdir)." + chmod 0700 "$tmpdir" + fi + #info "Using $tmpdir as TMPDIR" + precmd="${precmd}TMPDIR=$tmpdir " + fi + + ### Source + + set -o noglob + + # excludes + SAVEIFS=$IFS + IFS=$(echo -en "\n\b") + for i in $exclude; do + str="${i//__star__/*}" + execstr_source="${execstr_source} --exclude '$str'" + done + IFS=$SAVEIFS + + # includes + SAVEIFS=$IFS + IFS=$(echo -en "\n\b") + for i in $include; do + [ "$i" != "/" ] || fatal "Sorry, you cannot use 'include = /'" + str="${i//__star__/*}" + execstr_source="${execstr_source} --include '$str'" + done + IFS=$SAVEIFS + + set +o noglob + + execstr_options="${execstr_options} --ssh-options '$sshoptions'" + if [ "$bandwidthlimit" != 0 ]; then + [ -z "$desturl" ] || warning 'The bandwidthlimit option is not used when desturl is set.' + execstr_precmd="trickle -s -d $bandwidthlimit -u $bandwidthlimit" + fi +} + +function findlastdates(){ + outputfile=$1 + lastfull=0 + lastinc=0 + backuptime=0 + + while read line; do + atime=0 + arr=() + sort='' + test=$(echo $line|awk '{if (NF == 7); if ($1 == "Full" || $1 == "Incremental") {print $4, $3, $6, $5}}' ) + + if [ -n "$test" ]; then + backuptime=$(date -u -d "$test" +%s) + + arr=($(echo $line|awk '{print $1, $2, $3, $4, $5, $6}')) + if [ ${arr[0]} == "Incremental" ] && [ "$lastinc" -lt "$backuptime" ] ; then + lastinc=$backuptime + elif [ ${arr[0]} == "Full" ] && [ "$lastfull" -lt "$backuptime" ] ; then + lastfull=$backuptime + fi + + fi + + done < $outputfile + # a full backup can be seen as incremental too + lastinc=$(echo $lastinc | awk 'max=="" || $1 > max {max=$1} END{ print max}') +} + +function check_status() { + grep -q 'No orphaned or incomplete backup sets found.' $1 + if [ $? -ne 0 ] ; then + exit 2 + fi +} + +## +## this function handles the freshness check of a backup action +## + +function process_action() { + local file="$1" + local suffix="$2" + setfile $file + get_dupconf $1 + mangle_cli + + outputfile=`maketemp backupout` + export PASSPHRASE=$password + export FTP_PASSWORD=$ftp_password + output=` su -c \ + "$execstr_precmd duplicity $execstr_options collection-status $execstr_serverpart >$outputfile 2>&1"` + #echo "$execstr_precmd duplicity $execstr_options collection-status $execstr_serverpart" >$outputfile + exit_code=$? + echo -n $outputfile + + #check_status + #findlastdates +} + +files=`find $configdirectory -follow -mindepth 1 -maxdepth 1 -type f ! -name '.*.swp' | sort -n` + +for file in $files; do + [ -f "$file" ] || continue + suffix="${file##*.}" + base=`basename $file` + if [ "${base:0:1}" == "0" -o "$suffix" == "disabled" ]; then + continue + fi + if [ -e "$scriptdirectory/$suffix" -a "$suffix" == "dup" ]; then + process_action $file $suffix + fi +done + diff --git a/files/nagios_plugins/duplicity/check_backupninja_duplicity.py b/files/nagios_plugins/duplicity/check_backupninja_duplicity.py new file mode 100644 index 0000000..5deeccb --- /dev/null +++ b/files/nagios_plugins/duplicity/check_backupninja_duplicity.py @@ -0,0 +1,118 @@ +#!/usr/bin/env python + +# Inspired by Arne Schwabe [with BSD license] +# Inspired by backupninja [that's gpl some version] +# minor changes by someon who doesn't understand all the license quirks + +from subprocess import Popen,PIPE +import sys +import time +import os +import argparse +import getopt + +def main(): + # getopt = much more writing + + parser = argparse.ArgumentParser(description='Nagios Duplicity status checker') + + parser.add_argument("-w", dest="warninc", default=28, type=int, + help="Number of hours allowed for incremential backup warning level") + parser.add_argument("-W", dest="warnfull", default=40, type=int, + help="Number of hours allowed for incremential backup critical level") + + parser.add_argument("-c", dest="critinc", default=52, type=int, + help="Number of days allowed for full backup warning level") + + parser.add_argument("-C", dest="critfull", default=60, type=int, + help="Number of days allowed for full backup critical level") + + args = parser.parse_args() + + okay = 0 + + #f = open ('/tmp/tmp.q5Mqui6nVr/backupout.amDtCIcW', 'r') + #output = f.read() + + # *sigh* check_output is from python 2.7 and onwards. Debian, upgrade yourself. + #output , err = check_output(['/root/freshness.sh']) + + if os.path.isfile("/usr/lib/nagios/plugins/backupninja_duplicity_freshness.sh") and os.access("/usr/lib/nagios/plugins/backupninja_duplicity_freshness.sh", os.X_OK): + checkstatus, err = Popen(['/bin/bash', '/usr/lib/nagios/plugins/backupninja_duplicity_freshness.sh'], stdout=PIPE, stderr=PIPE, env={'HOME': '/root', 'PATH': os.environ['PATH']}).communicate() + elif os.path.isfile("/usr/local/lib/nagios/plugins/backupninja_duplicity_freshness.sh") and os.access("/usr/local/lib/nagios/plugins/backupninja_duplicity_freshness.sh", os.X_OK): + checkstatus, err = Popen(['/bin/bash', '/usr/local/lib/nagios/plugins/backupninja_duplicity_freshness.sh'], stdout=PIPE, stderr=PIPE, env={'HOME': '/root', 'PATH': os.environ['PATH']}).communicate() + + # Don't use exec(), popen(), etc. to execute external commands without explicity using the full path of the external program. Hijacked search path could be problematic. + #checkstatus, err = Popen(['/bin/bash', './freshness.sh'], stdout=PIPE, stderr=PIPE, env={'HOME': '/root', 'PATH': os.environ['PATH']}).communicate() + + f = open (checkstatus) + output = f.read() + + lastfull, lastinc = findlastdates(output) + + sincelastfull = time.time() - lastfull + sincelastinc = time.time() - lastinc + + msg = "OK: " + + if sincelastfull > (args.warnfull * 24 * 3600) or sincelastinc > (args.warninc * 3600): + okay = 1 + msg = "WARNING: " + + if sincelastfull > (args.critfull * 24 * 3600) or sincelastinc > (args.critinc * 3600): + okay = 2 + msg = "CRITICAL: " + + if not checkoutput(output): + okay = max(okay,1) + msg = "WARNING: duplicity output: %s " % repr(output) + + if err: + okay=2 + msg = "Unexpected output: %s, " % repr(err) + + print msg, "last full %s ago, last incremential %s ago|lastfull=%d, lastinc=%d" % ( formattime(sincelastfull), formattime(sincelastinc), sincelastfull, sincelastinc) + sys.exit(okay) + +def checkoutput(output): + if output.find("No orphaned or incomplete backup sets found.")==-1: + return False + + return True + +def formattime(seconds): + days = seconds / (3600 * 24) + hours = seconds / 3600 % 24 + + if days: + return "%d days %d hours" % (days,hours) + else: + return "%d hours" % hours + + +def findlastdates(output): + lastfull =0 + lastinc = 0 + + for line in output.split("\n"): + parts = line.split() + + # ['Incremental', 'Sun', 'Oct', '31', '03:00:04', '2010', '1'] + if len (parts) == 7 and parts[0] in ["Full","Incremental"]: + foo = time.strptime(" ".join(parts[1:6]),"%a %b %d %H:%M:%S %Y") + + backuptime = time.mktime(foo) + + if parts[0] == "Incremental" and lastinc < backuptime: + lastinc = backuptime + elif parts[0] == "Full" and lastfull < backuptime: + lastfull = backuptime + + + # Count a full backup as incremental backup + lastinc = max(lastfull,lastinc) + return (lastfull, lastinc) + + +if __name__=='__main__': + main() diff --git a/manifests/nagios_plugin/duplicity.pp b/manifests/nagios_plugin/duplicity.pp new file mode 100644 index 0000000..93b0989 --- /dev/null +++ b/manifests/nagios_plugin/duplicity.pp @@ -0,0 +1,22 @@ +class backupninja::nagios_plugin::duplicity { + case ::operatingsystem { + 'Debian': { package { 'python-argparse': ensure => installed, } } + 'Ubuntu': { package { 'python-argh': ensure => installed, } } + default: { + notify {'Backupninja-Duplicity Nagios check needs python-argparse to be installed !':} } + } + + nagios::plugin { 'check_backupninja_duplicity.py': + source => 'backupninja/nagios_plugins/duplicity/check_backupninja_duplicity.py' + } + + # deploy helper script + file { '/usr/lib/nagios/plugins/backupninja_duplicity_freshness.sh': + source => 'puppet:///modules/backupninja/nagios_plugins/duplicity/backupninja_duplicity_freshness.sh', + mode => '0755', + owner => 'nagios', + group => 'nagios', + } + +} + -- cgit v1.2.3 From f17052b041c183cfb765ae423f29143ed85142d6 Mon Sep 17 00:00:00 2001 From: varac Date: Thu, 24 Jan 2013 13:32:00 +0100 Subject: added nrpe cmd and service definition --- manifests/nagios_plugin/duplicity.pp | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/manifests/nagios_plugin/duplicity.pp b/manifests/nagios_plugin/duplicity.pp index 93b0989..5280136 100644 --- a/manifests/nagios_plugin/duplicity.pp +++ b/manifests/nagios_plugin/duplicity.pp @@ -1,13 +1,16 @@ class backupninja::nagios_plugin::duplicity { - case ::operatingsystem { + case $::operatingsystem { 'Debian': { package { 'python-argparse': ensure => installed, } } 'Ubuntu': { package { 'python-argh': ensure => installed, } } default: { notify {'Backupninja-Duplicity Nagios check needs python-argparse to be installed !':} } } - nagios::plugin { 'check_backupninja_duplicity.py': - source => 'backupninja/nagios_plugins/duplicity/check_backupninja_duplicity.py' + file { '/usr/lib/nagios/plugins/check_backupninja_duplicity.py': + source => 'puppet:///modules/backupninja/nagios_plugins/duplicity/check_backupninja_duplicity.py', + mode => '0755', + owner => 'nagios', + group => 'nagios', } # deploy helper script @@ -18,5 +21,17 @@ class backupninja::nagios_plugin::duplicity { group => 'nagios', } -} + nagios::nrpe::command { 'check_backupninja_duplicity': + command_line => "${::nagios::nrpe::nagios_plugin_dir}/check_backupninja_duplicity" + } + nagios::service { 'Backupninja Duplicity': + use_nrpe => true, + check_command => 'check_backupninja_duplicity', + nrpe_timeout => '60', + # check only twice a day + normal_check_interval => '720', + # recheck every hour + retry_check_interval => '60', + } +} -- cgit v1.2.3 From 5a0c12cd255194946d5acbd3031ac412e56d8100 Mon Sep 17 00:00:00 2001 From: varac Date: Thu, 24 Jan 2013 16:52:42 +0100 Subject: call Backupninja Duplicity with fqdn so it is a unique name --- manifests/nagios_plugin/duplicity.pp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manifests/nagios_plugin/duplicity.pp b/manifests/nagios_plugin/duplicity.pp index 5280136..d0abe49 100644 --- a/manifests/nagios_plugin/duplicity.pp +++ b/manifests/nagios_plugin/duplicity.pp @@ -25,7 +25,7 @@ class backupninja::nagios_plugin::duplicity { command_line => "${::nagios::nrpe::nagios_plugin_dir}/check_backupninja_duplicity" } - nagios::service { 'Backupninja Duplicity': + nagios::service { 'Backupninja Duplicity $::fqdn': use_nrpe => true, check_command => 'check_backupninja_duplicity', nrpe_timeout => '60', -- cgit v1.2.3 From 9be6a4183f734bc83c0a40f806775143e9b89fa0 Mon Sep 17 00:00:00 2001 From: varac Date: Thu, 24 Jan 2013 16:55:43 +0100 Subject: double quote variable --- manifests/nagios_plugin/duplicity.pp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manifests/nagios_plugin/duplicity.pp b/manifests/nagios_plugin/duplicity.pp index d0abe49..b88f64c 100644 --- a/manifests/nagios_plugin/duplicity.pp +++ b/manifests/nagios_plugin/duplicity.pp @@ -25,7 +25,7 @@ class backupninja::nagios_plugin::duplicity { command_line => "${::nagios::nrpe::nagios_plugin_dir}/check_backupninja_duplicity" } - nagios::service { 'Backupninja Duplicity $::fqdn': + nagios::service { "Backupninja Duplicity $::fqdn": use_nrpe => true, check_command => 'check_backupninja_duplicity', nrpe_timeout => '60', -- cgit v1.2.3 From 6535aaa54d141d7605af2a62af5b6b2796af751c Mon Sep 17 00:00:00 2001 From: varac Date: Thu, 24 Jan 2013 18:03:32 +0100 Subject: sudo def for duplicity check --- manifests/nagios_plugin/duplicity.pp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/manifests/nagios_plugin/duplicity.pp b/manifests/nagios_plugin/duplicity.pp index b88f64c..8be455b 100644 --- a/manifests/nagios_plugin/duplicity.pp +++ b/manifests/nagios_plugin/duplicity.pp @@ -22,7 +22,13 @@ class backupninja::nagios_plugin::duplicity { } nagios::nrpe::command { 'check_backupninja_duplicity': - command_line => "${::nagios::nrpe::nagios_plugin_dir}/check_backupninja_duplicity" + command_line => "sudo {::nagios::nrpe::nagios_plugin_dir}/check_backupninja_duplicity.py" + } + sudo::spec {'nrpe_check_backupninja_duplicity': + ensure => present, + users => 'nagios', + hosts => 'ALL', + commands => "sudo {::nagios::nrpe::nagios_plugin_dir}/check_backupninja_duplicity.py"; } nagios::service { "Backupninja Duplicity $::fqdn": @@ -34,4 +40,6 @@ class backupninja::nagios_plugin::duplicity { # recheck every hour retry_check_interval => '60', } + + } -- cgit v1.2.3 From 59b07951b7ad39d9422bdd94fd5c7ea4362b0878 Mon Sep 17 00:00:00 2001 From: varac Date: Thu, 24 Jan 2013 18:06:33 +0100 Subject: typo at cmd def --- manifests/nagios_plugin/duplicity.pp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/manifests/nagios_plugin/duplicity.pp b/manifests/nagios_plugin/duplicity.pp index 8be455b..d24aab2 100644 --- a/manifests/nagios_plugin/duplicity.pp +++ b/manifests/nagios_plugin/duplicity.pp @@ -22,13 +22,13 @@ class backupninja::nagios_plugin::duplicity { } nagios::nrpe::command { 'check_backupninja_duplicity': - command_line => "sudo {::nagios::nrpe::nagios_plugin_dir}/check_backupninja_duplicity.py" + command_line => "sudo ${::nagios::nrpe::nagios_plugin_dir}/check_backupninja_duplicity.py" } sudo::spec {'nrpe_check_backupninja_duplicity': ensure => present, users => 'nagios', hosts => 'ALL', - commands => "sudo {::nagios::nrpe::nagios_plugin_dir}/check_backupninja_duplicity.py"; + commands => "sudo ${::nagios::nrpe::nagios_plugin_dir}/check_backupninja_duplicity.py"; } nagios::service { "Backupninja Duplicity $::fqdn": -- cgit v1.2.3 From d7345c06a7bb9f1b76ec57496ad99f68c6b0c5f4 Mon Sep 17 00:00:00 2001 From: varac Date: Thu, 24 Jan 2013 18:11:42 +0100 Subject: NOPASSWD: for nagios check --- manifests/nagios_plugin/duplicity.pp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manifests/nagios_plugin/duplicity.pp b/manifests/nagios_plugin/duplicity.pp index d24aab2..7dbd263 100644 --- a/manifests/nagios_plugin/duplicity.pp +++ b/manifests/nagios_plugin/duplicity.pp @@ -28,7 +28,7 @@ class backupninja::nagios_plugin::duplicity { ensure => present, users => 'nagios', hosts => 'ALL', - commands => "sudo ${::nagios::nrpe::nagios_plugin_dir}/check_backupninja_duplicity.py"; + commands => "NOPASSWD: ${::nagios::nrpe::nagios_plugin_dir}/check_backupninja_duplicity.py"; } nagios::service { "Backupninja Duplicity $::fqdn": -- cgit v1.2.3 From daeb1a1f112a4dbf6b39565f0dea461e46a64681 Mon Sep 17 00:00:00 2001 From: kwadronaut Date: Thu, 31 Jan 2013 10:15:44 +0100 Subject: updating nagios scripts --- .../duplicity/backupninja_duplicity_freshness.sh | 58 +++++++++++----------- .../duplicity/check_backupninja_duplicity.py | 47 ++++++++++-------- 2 files changed, 55 insertions(+), 50 deletions(-) diff --git a/files/nagios_plugins/duplicity/backupninja_duplicity_freshness.sh b/files/nagios_plugins/duplicity/backupninja_duplicity_freshness.sh index ea694d0..7af2bf7 100644 --- a/files/nagios_plugins/duplicity/backupninja_duplicity_freshness.sh +++ b/files/nagios_plugins/duplicity/backupninja_duplicity_freshness.sh @@ -1,3 +1,4 @@ +#!/bin/bash # -*- mode: sh; sh-basic-offset: 3; indent-tabs-mode: nil; -*- # vim: set filetype=sh sw=3 sts=3 expandtab autoindent: @@ -192,34 +193,34 @@ function mangle_cli(){ fi } -function findlastdates(){ - outputfile=$1 - lastfull=0 - lastinc=0 - backuptime=0 - - while read line; do - atime=0 - arr=() - sort='' - test=$(echo $line|awk '{if (NF == 7); if ($1 == "Full" || $1 == "Incremental") {print $4, $3, $6, $5}}' ) - - if [ -n "$test" ]; then - backuptime=$(date -u -d "$test" +%s) - - arr=($(echo $line|awk '{print $1, $2, $3, $4, $5, $6}')) - if [ ${arr[0]} == "Incremental" ] && [ "$lastinc" -lt "$backuptime" ] ; then - lastinc=$backuptime - elif [ ${arr[0]} == "Full" ] && [ "$lastfull" -lt "$backuptime" ] ; then - lastfull=$backuptime - fi - - fi - - done < $outputfile - # a full backup can be seen as incremental too - lastinc=$(echo $lastinc | awk 'max=="" || $1 > max {max=$1} END{ print max}') -} +#function findlastdates(){ +# outputfile=$1 +# lastfull=0 +# lastinc=0 +# backuptime=0 +# +# while read line; do +# atime=0 +# arr=() +# sort='' +# test=$(echo $line|awk '{if (NF == 7); if ($1 == "Full" || $1 == "Incremental") {print $4, $3, $6, $5}}' ) +# +# if [ -n "$test" ]; then +# backuptime=$(date -u -d "$test" +%s) +# +# arr=($(echo $line|awk '{print $1, $2, $3, $4, $5, $6}')) +# if [ ${arr[0]} == "Incremental" ] && [ "$lastinc" -lt "$backuptime" ] ; then +# lastinc=$backuptime +# elif [ ${arr[0]} == "Full" ] && [ "$lastfull" -lt "$backuptime" ] ; then +# lastfull=$backuptime +# fi +# +# fi +# +# done < $outputfile +# # a full backup can be seen as incremental too +# lastinc=$(echo $lastinc | awk 'max=="" || $1 > max {max=$1} END{ print max}') +#} function check_status() { grep -q 'No orphaned or incomplete backup sets found.' $1 @@ -244,7 +245,6 @@ function process_action() { export FTP_PASSWORD=$ftp_password output=` su -c \ "$execstr_precmd duplicity $execstr_options collection-status $execstr_serverpart >$outputfile 2>&1"` - #echo "$execstr_precmd duplicity $execstr_options collection-status $execstr_serverpart" >$outputfile exit_code=$? echo -n $outputfile diff --git a/files/nagios_plugins/duplicity/check_backupninja_duplicity.py b/files/nagios_plugins/duplicity/check_backupninja_duplicity.py index 5deeccb..8ed9ce6 100644 --- a/files/nagios_plugins/duplicity/check_backupninja_duplicity.py +++ b/files/nagios_plugins/duplicity/check_backupninja_duplicity.py @@ -13,27 +13,20 @@ import getopt def main(): # getopt = much more writing - parser = argparse.ArgumentParser(description='Nagios Duplicity status checker') parser.add_argument("-w", dest="warninc", default=28, type=int, - help="Number of hours allowed for incremential backup warning level") - parser.add_argument("-W", dest="warnfull", default=40, type=int, - help="Number of hours allowed for incremential backup critical level") - + help="Number of hours allowed for incremential backup warning level, default 28") + parser.add_argument("-W", dest="warnfull", default=31, type=int, + help="Number of days allowed for full backup warning level, default 31") parser.add_argument("-c", dest="critinc", default=52, type=int, - help="Number of days allowed for full backup warning level") - - parser.add_argument("-C", dest="critfull", default=60, type=int, - help="Number of days allowed for full backup critical level") - + help="Number of hours allowed for incremential backup critical level, default 52") + parser.add_argument("-C", dest="critfull", default=33, type=int, + help="Number of days allowed for full backup critical level, default 33") args = parser.parse_args() okay = 0 - #f = open ('/tmp/tmp.q5Mqui6nVr/backupout.amDtCIcW', 'r') - #output = f.read() - # *sigh* check_output is from python 2.7 and onwards. Debian, upgrade yourself. #output , err = check_output(['/root/freshness.sh']) @@ -45,8 +38,20 @@ def main(): # Don't use exec(), popen(), etc. to execute external commands without explicity using the full path of the external program. Hijacked search path could be problematic. #checkstatus, err = Popen(['/bin/bash', './freshness.sh'], stdout=PIPE, stderr=PIPE, env={'HOME': '/root', 'PATH': os.environ['PATH']}).communicate() - f = open (checkstatus) - output = f.read() + #another sigh: Debian testing, upgrade yourself, this is only needed because Debian testing uses duplicity 0.6.18-3 + # open file read/write + f = open (checkstatus,"r") + checklines = f.readlines() + f.close() + + # remove the line that says Import of duplicity.backends.giobackend Failed: No module named gio + f = open(checkstatus,"w") + for line in checklines: + if not 'Import of duplicity.backends.giobackend Failed: No module named gio' in line: + f.write(line) + f.close() + + output = open(checkstatus).read() lastfull, lastinc = findlastdates(output) @@ -58,26 +63,26 @@ def main(): if sincelastfull > (args.warnfull * 24 * 3600) or sincelastinc > (args.warninc * 3600): okay = 1 msg = "WARNING: " - if sincelastfull > (args.critfull * 24 * 3600) or sincelastinc > (args.critinc * 3600): okay = 2 msg = "CRITICAL: " - if not checkoutput(output): okay = max(okay,1) msg = "WARNING: duplicity output: %s " % repr(output) - if err: okay=2 msg = "Unexpected output: %s, " % repr(err) print msg, "last full %s ago, last incremential %s ago|lastfull=%d, lastinc=%d" % ( formattime(sincelastfull), formattime(sincelastinc), sincelastfull, sincelastinc) + + #clean up cruft + os.remove(checkstatus) sys.exit(okay) def checkoutput(output): - if output.find("No orphaned or incomplete backup sets found.")==-1: + if not 'No orphaned or incomplete backup sets found.' in output: return False - + return True def formattime(seconds): @@ -91,7 +96,7 @@ def formattime(seconds): def findlastdates(output): - lastfull =0 + lastfull = 0 lastinc = 0 for line in output.split("\n"): -- cgit v1.2.3