Skip to content
Snippets Groups Projects
dup.in 11.6 KiB
Newer Older
  • Learn to ignore specific revisions
  • # -*- mode: sh; sh-basic-offset: 3; indent-tabs-mode: nil; -*-
    
    # vim: set filetype=sh sw=3 sts=3 expandtab autoindent:
    
    elijah's avatar
    elijah committed
    #
    # duplicity script for backupninja
    
    # requires duplicity >= 0.4.4, and >= 0.4.9 when using a custom tmpdir.
    
    elijah's avatar
    elijah committed
    #
    
    getconf options
    
    getconf testconnect yes
    getconf nicelevel 0
    
    
    setsection gpg
    getconf password
    getconf sign no
    getconf encryptkey
    
    elijah's avatar
    elijah committed
    getconf include
    
    getconf vsnames all
    getconf vsinclude
    
    elijah's avatar
    elijah committed
    getconf exclude
    
    getconf increments 30
    
    getconf awsaccesskeyid
    getconf awssecretaccesskey
    
    getconf cfusername
    getconf cfapikey
    getconf cfauthurl
    
    intrigeri's avatar
    intrigeri committed
    getconf ftp_password
    
    getconf bandwidthlimit 0
    
    elijah's avatar
    elijah committed
    getconf desthost
    getconf destdir
    getconf destuser
    destdir=${destdir%/}
    
    
    ### SANITY CHECKS ##############################################################
    
    elijah's avatar
    elijah committed
    
    
    [ -n "$desturl" -o -n "$destdir" ]  || fatal "The destination directory (destdir) must be set when desturl is not used."
    
    [ -n "$include" -o -n "$vsinclude" ]  || fatal "No source includes specified"
    
    [ -n "$password" ] || fatal "The password option must be set."
    
    if [ "`echo $desturl | @AWK@ -F ':' '{print $1}'`" == "s3+http" ]; then
       [ -n "$awsaccesskeyid" -a -n "$awssecretaccesskey" ]  || fatal "AWS access keys must be set for S3 backups."
    fi
    
    if [ "`echo $desturl | @AWK@ -F ':' '{print $1}'`" == "cf+http" ]; then
       [ -n "$cfusername" -a -n "$cfapikey" ]  || fatal "Cloudfiles access keys must be set for S3 backups."
    fi
    
    intrigeri's avatar
    intrigeri committed
    if [ "`echo $desturl | @AWK@ -F ':' '{print $1}'`" == "ftp" ]; then
       [ -n "$ftp_password" ]  || fatal "ftp_password must be set for FTP backups."
    fi
    
    ### VServers
    
    # If vservers are configured, check that the ones listed in $vsnames do exist.
    
    if [ $vservers_are_available = yes ]; then
       if [ "$vsnames" = all ]; then
          vsnames="$found_vservers"
       else
          if ! vservers_exist "$vsnames" ; then
                fatal "At least one of the vservers listed in vsnames ($vsnames) does not exist."
          fi
       fi
       if [ -n "$vsinclude" ]; then
          info "Using vservers '$vsnames'"
          usevserver=yes
       fi
    
    else
       [ -z "$vsinclude" ] || warning 'vservers support disabled in backupninja.conf, vsincludes configuration lines will be ignored'
    
    ### See if we can login on $desthost
    
       if [ -n "$desturl" ]; then
          warning 'testconnect can not be used when desturl is set'
       else
          debug "ssh $sshoptions -o PasswordAuthentication=no $desthost -l $destuser 'echo -n 1'"
          if [ ! $test ]; then
             result=`ssh $sshoptions -o PasswordAuthentication=no $desthost -l $destuser 'echo -n 1'`
             if [ "$result" != "1" ]; then
    
                fatal "Can't connect to $desthost as $destuser."
    
                debug "Connected to $desthost as $destuser successfully"
    
    elijah's avatar
    elijah committed
    fi
    
    
    ### COMMAND-LINE MANGLING ######################################################
    
    ### initialize $execstr*
    
    execstr_precmd=
    
    execstr_command=
    execstr_options="$options --no-print-statistics"
    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
    
    ### duplicity version (ignore anything else than 0-9 and ".")
    duplicity_version="`duplicity --version | @AWK@ '{print $2}' | @SED@ 's/[^.[:digit:]]//g'`"
    
    duplicity_major="`echo $duplicity_version | @AWK@ -F '.' '{print $1}'`"
    duplicity_minor="`echo $duplicity_version | @AWK@ -F '.' '{print $2}'`"
    duplicity_sub="`echo $duplicity_version | @AWK@ -F '.' '{print $3}'`"
    
    ### ssh/scp/sftp options (duplicity < 0.4.3 is unsupported)
    
    ## duplicity >= 0.6.17 : paramiko backend
    if [ "$duplicity_major" -ge 0 -a "$duplicity_minor" -ge 6 -a "$duplicity_sub" -ge 17 ]; then
       if [ -n "$sshoptions" ]; then
          echo "$sshoptions" | grep -Eqs '^-o[[:space:]]*IdentityFile=[^ ]+$' \
             || warning 'duplicity >= 0.6.17 only supports the IdentityFile SSH option'
       fi
       execstr_options="${execstr_options} --ssh-options '$sshoptions'"
    
       # FIXME: use trickle
       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
    
    ## duplicity < 0.6.17 : scp/sftp backend
    else
       scpoptions="$sshoptions"
       if [ "$bandwidthlimit" != 0 ]; then
          [ -z "$desturl" ] || warning 'The bandwidthlimit option is not used when desturl is set.'
          scpoptions="$scpoptions -l $bandwidthlimit"
       fi
       sftpoptions="$sshoptions"
       execstr_options="${execstr_options} --scp-command 'scp $scpoptions' --sftp-command 'sftp $sftpoptions'"
    
    ### Symmetric or asymmetric (public/private key pair) encryption
    
       execstr_options="${execstr_options} --encrypt-key $encryptkey"
       debug "Data will be encrypted with the GnuPG key $encryptkey."
    
       debug "Data will be encrypted using symmetric encryption."
    
    ### Data signing (or not)
    
       # 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"
       debug "Data will be signed will the GnuPG key $signkey."
    
       debug "Data won't be signed."
    
    ### Incremental or full backup mode
    # If incremental==yes, use the default duplicity behaviour: perform an
    # incremental backup if old signatures can be found, else switch to
    # full backup.
    # If incremental==no, force a full backup anyway.
    if [ "$incremental" == "no" ]; then
    
       # we're in incremental mode
       if [ "$increments" != "keep" ]; then
          # if we don't want to keep every increments
          if [ "`echo $increments | tr -d 0-9`" == "" ]; then
             increments="${increments}D"
    
          execstr_options="${execstr_options} --full-if-older-than $increments"
    
    elijah's avatar
    elijah committed
    fi
    
    
    execstr_options="${execstr_options} --extra-clean"
    
    ### Temporary directory
    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"
    
       execstr_options="${execstr_options} --tempdir '$tmpdir'"
    
    # duplicity now enables the archive_dir by default, let's put it into /var/cache/backupninja/duplicity
    
    if echo "${options}" | grep -qv -- "--archive-dir" ; then
       execstr_options="${execstr_options} --archive-dir /var/cache/backupninja/duplicity"
    
    ### Cleanup old backup sets (or not)
    if [ "$keep" != "yes" ]; then
       if [ "`echo $keep | tr -d 0-9`" == "" ]; then
          keep="${keep}D"
       fi
    fi
    
    ### Source
    
    elijah's avatar
    elijah committed
    
    
    elijah's avatar
    elijah committed
    # excludes
    
    SAVEIFS=$IFS
    IFS=$(echo -en "\n\b")
    
       execstr_source="${execstr_source} --exclude '$str'"
    
    elijah's avatar
    elijah committed
    done
    
    
    # includes
    
    SAVEIFS=$IFS
    IFS=$(echo -en "\n\b")
    
       [ "$i" != "/" ] || fatal "Sorry, you cannot use 'include = /'"
    
       execstr_source="${execstr_source} --include '$str'"
    
    elijah's avatar
    elijah committed
    done
    
    elijah's avatar
    elijah committed
    
    
    if [ $usevserver = yes ]; then
    
          SAVEIFS=$IFS
          IFS=$(echo -en "\n\b")
    
             str="${vi//__star__/*}"
             str="$VROOTDIR/$vserver$str"
             execstr_source="${execstr_source} --include '$str'"
    
    ### EXECUTE ####################################################################
    
    execstr_source=${execstr_source//\\*/\\\\\\*}
    
    
    ### If desturl is an S3 URL export the AWS environment variables
    if [ "`echo $desturl | @AWK@ -F ':' '{print $1}'`" == "s3+http" ]; then
       export AWS_ACCESS_KEY_ID="$awsaccesskeyid"
       export AWS_SECRET_ACCESS_KEY="$awssecretaccesskey"
    fi
    
    
    ### If desturl is a RackSpace's CloudFiles URL export the relevant
    ### environment variables
    if [ "`echo $desturl | @AWK@ -F ':' '{print $1}'`" == "cf+http" ]; then
       export CLOUDFILES_USERNAME="$cfusername"
       export CLOUDFILES_APIKEY="$cfapikey"
       if [ -n "$cfauthurl" ]; then
          export CLOUDFILES_AUTHURL="$cfauthurl"
       fi
    fi
    
    
    ### Cleanup commands (duplicity >= 0.4.4)
    
    # cleanup
    
    debug "$execstr_precmd duplicity cleanup --force $execstr_options $execstr_serverpart"
    
    if [ ! $test ]; then
       export PASSPHRASE=$password
       export FTP_PASSWORD=$ftp_password
       output=`nice -n $nicelevel \
                 su -c \
    
                 "$execstr_precmd duplicity cleanup --force $execstr_options $execstr_serverpart 2>&1"`
    
       exit_code=$?
       if [ $exit_code -eq 0 ]; then
          debug $output
          info "Duplicity cleanup finished successfully."
       else
          debug $output
          warning "Duplicity cleanup failed."
       fi
    fi
    
    # remove-older-than
    if [ "$keep" != "yes" ]; then
    
       debug "$execstr_precmd duplicity remove-older-than $keep --force $execstr_options $execstr_serverpart"
    
       if [ ! $test ]; then
          export PASSPHRASE=$password
    
    intrigeri's avatar
    intrigeri committed
          export FTP_PASSWORD=$ftp_password
    
          output=`nice -n $nicelevel \
    
                    "$execstr_precmd duplicity remove-older-than $keep --force $execstr_options $execstr_serverpart 2>&1"`
    
          exit_code=$?
          if [ $exit_code -eq 0 ]; then
    
             debug $output
    
             info "Duplicity remove-older-than finished successfully."
    
             debug $output
    
             warning "Duplicity remove-older-than failed."
    
    elijah's avatar
    elijah committed
    
    
    # remove-all-inc-of-but-n-full : remove increments of older full backups : only keep latest ones
    if [ "$keep" != "yes" ]; then
       if [ "$keepincroffulls" != "all" ]; then
    
          if [ "$duplicity_major" -ge 0 -a "$duplicity_minor" -ge 6 -a "$duplicity_sub" -ge 10 ]; then
    
             debug "$execstr_precmd duplicity remove-all-inc-of-but-n-full $keepincroffulls --force $execstr_options $execstr_serverpart"
    
             if [ ! $test ]; then
                export PASSPHRASE=$password
                export FTP_PASSWORD=$ftp_password
                output=`nice -n $nicelevel \
                   su -c \
    
                   "$execstr_precmd duplicity remove-all-inc-of-but-n-full $keepincroffulls --force $execstr_options $execstr_serverpart 2>&1"`
    
                exit_code=$?
                if [ $exit_code -eq 0 ]; then
                   debug $output
                   info "Duplicity remove-all-inc-of-but-n-full finished successfully."
                else
                   debug $output
                   warning "Duplicity remove-all-inc-of-but-n-full failed."
                fi
             fi
          fi
       fi
    fi
    
    
    ### Backup command
    
    debug "$execstr_precmd duplicity $execstr_command $execstr_options $execstr_source --exclude '**' / $execstr_serverpart"
    
    elijah's avatar
    elijah committed
    if [ ! $test ]; then
    
       export PASSPHRASE=$password
    
    intrigeri's avatar
    intrigeri committed
       export FTP_PASSWORD=$ftp_password
    
       output=`nice -n $nicelevel \
                 su -c \
    
                    "$execstr_precmd duplicity $execstr_command $execstr_options $execstr_source --exclude '**' / $execstr_serverpart >$outputfile 2>&1"`
    
       exit_code=$?
    
       debug $output
       cat $outputfile | (while read output ; do
    
       if [ $exit_code -eq 0 ]; then
          info "Duplicity finished successfully."
       else
          fatal "Duplicity failed."
       fi
    
    elijah's avatar
    elijah committed
    
    return 0