Puppet: System Administration Automated

Puppet Training Schedule
Next Class July 27-29
New York, New York
Discount before July 1st

rdiff-backup recipe

Use rdiff-backup to make regular copies of a directory.

Problem:

Of course we all want to backup our valuable data, but managing backups can be so annoying :-) So I wrote a simple type, that can simplify backups. I'm using a simple tool rdiff-backup. The type backup is a wrapper of the file type, that backups a directory regularly and restores the content if the directory is not present. It can also be used to bootstrap a directory from another source, and then do the backup.

Solution

# a wrapper of file type with backup facilities
define backup ($path=false, $server="/var/backup", $destination=false,
        $restore=false, $ensure=directory,
        $owner=false, $group=false, $mode=false,
        $recurse=false, $source=false, $replace=false, $when=backup,
        $bootstrap=>false, $hardlink=false)
{
    # when to make the backup
    schedule { backup:
        range => "2-5",
        period => daily,
        repeat => 1
    }
    if $path { } else { $path=$name }
    # where to copy file
    $backup_dest = $destination ? {
        # sane defaults
        false => "$server/$path",
        default => "$server/$destination"
    }
    #backup the directory to $destination
    $program = "/usr/bin/rdiff-backup --create-full-path"
    $cp = $hardlink ? { true=>"cp -rl", default=>"cp -r" }
    $backupcmd = "$program $path $backup_dest"
    $restorecmd = "$program -r 1D $backup_dest $path || true"
    $b_strapcmd = "$cp $source $path || true"

    # run backup command on schedule
    exec { $backupcmd: schedule => $when }

    # run next commands first
    Exec {path=>"/bin:/usr/bin", creates => $path,
            before => [exec[$backupcmd],file[$name]]}
    # restore the directory or file if missing
    if $restore { exec { $restorecmd: }}
    # bootstrap if missing
    if $source {
        if $bootstrap
            { exec{ $b_strapcmd: require=>exec[$restorecmd]}}
        else
            { File { source=>$source }}
    }
    else
        { File { ensure=>$ensure }}

    if $mode { File { mode=>$mode }}
    if $group { File { group=>$group }}
    if $owner { File { owner=>$owner }}
    # manage file as normal
    file { $name:
            path=>$path,
            recurse=>$recurse,
            replace=>$replace
        }
}
 

We can use this as follows

# rdiff-backup has to be installed :-)
# this works on Debian and SuSE, other OS might have other names
package { "rdiff-backup": ensure=>present }

# we want to backup home to another machine called ''backupserver''.
Backup{ server => "backup@backupserver::/srv/backup" }
node default{
   backup {"/home":
      cron => true,
      destination => "$hostname/home",
   }
}

node webserver {
   # backups documentroot everytime puppet runs, and restores it in case we move the server to another machine
   backup {"/srv/www/example.com/htdocs":
      destination => "example.com/htdocs",
      restore => true,
   }
}

# On backupserver we use a special user ''backup'' for security.
node backupserver {
    user {"backup": home => "/srv/backup/", shell=>"/bin/sh" }
    file {"/srv/backup/": ensure=>directory, owner=>backup }
}

Discussion

In order to backup on the remote machine, we still have to manage ssh keys. In the above example, we have to add public keys from backup clients to /srv/backup/.ssh/authorized_keys.

...
command="/usr/bin/rdiff-backup --server" ssh-rsa ASA... = root@webserver
...

There's a recipe to administer SSH autorized_keys you might find interresting.

The restore feature might come in handy when moving services from one machine to another.

Care should be taken that two machines don't backup to the same location on the remote server. I have no idea how to avoid that, rather than appending $hostname to the backup path. But that makes restore feature less interesting.

Perhaps it would be nice for backup option of file type to have different providers, which would enable different backup schemes other than filebucket.